<pre class='metadata'>
Title: WebGPU Shading Language
Shortname: WGSL
Level: 1
Status: w3c/ED
Group: webgpu
URL: https://gpuweb.github.io/gpuweb/wgsl.html

!Participate: <a href="https://github.com/gpuweb/gpuweb/issues/new?labels=wgsl">File an issue</a> (<a href="https://github.com/gpuweb/gpuweb/issues?q=is%3Aissue+is%3Aopen+label%3Awgsl">open issues</a>)

Editor: dan sinclair, Google http://www.google.com, dsinclair@google.com
Editor: Myles C. Maxfield, Apple Inc., mmaxfield@apple.com, w3cid 77180
Abstract: Shading language for WebGPU.
Markup Shorthands: markdown yes
Markup Shorthands: idl no
</pre>

<style>
tr:nth-child(2n) {
  background-color: #f0f0f0;
}
thead {
  background-color: #f0f0f0;
  font-weight: bold;
}
.nowrap {
  white-space:nowrap;
}
</style>

# Introduction # {#intro}

<div class='example'>
  <xmp highlight='rust'>
    [[location 0]] var<out> gl_FragColor : vec4<f32>;
    fn main() -> void {
        gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
        return;
    }
    entry_point fragment = main;
  </xmp>
</div>


## Goals ## {#goals}

 * Trivially convertable to SPIR-V
 * Constructs are defined as normative references to their SPIR-V counterparts
 * All features in [SHORTNAME] are directly translatable to SPIR-V. (No polymorphism, no general pointers, no overloads, etc)
 * Features and semantics are exactly the ones of SPIR-V
 * Each item in this spec *must* provide the mapping to SPIR-V for the construct

## Technical Overview TODO ## {#technical-overview}

# Textual structure TODO # {#textual-structure}

TODO: This is a stub.

A [SHORTNAME] program is text.
This specification does not prescribe a particular encoding for that text.

## Comments ## {#comments}

Comments begin with a `#` and continue to the end of the current line. There are no multi-line comments.

TODO: What indicates the end of a line?  (E.g. A line ends at the next linefeed or at the end of the program)

## Tokens TODO ## {#tokens}

## Literals TODO ## {#literals}

<table class='data'>
  <thead>
    <tr><td>Token<td>Definition
  </thead>
  <tr><td>`FLOAT_LITERAL`<td>`(-?[0-9]*.[0-9]+ | -?[0-9]+.[0-9]*)(e(+|-)?[0-9]+)?`
  <tr><td>`INT_LITERAL`<td>`-?0x[0-9a-fA-F]+ | 0 | -?[1-9][0-9]*`
  <tr><td>`UINT_LITERAL`<td>`0x[0-9a-fA-F]+u | 0u | [1-9][0-9]*u`
  <tr><td>`STRING_LITERAL`<td>`"[^"]*"`
</table>

Note: literals are parsed greedy. This means that for statements like `a -5`
      this will *not* parse as `a` `minus` `5` but instead as `a` `-5` which
      may be unexpected. A space must be inserted after the `-` if the first
      expression is desired.

<pre class='def'>
const_literal
  : INT_LITERAL
  | UINT_LITERAL
  | FLOAT_LITERAL
  | TRUE
  | FALSE
</pre>


## Keywords TODO ## {#keywords}

TODO: *Stub*

See [[#keyword-summary]] for a list of keywords.

## Identifiers TODO ## {#identifiers}

<table class='data'>
  <thead>
    <tr><td>Token<td>Definition
  </thead>
  <tr><td>`IDENT`<td>`[a-zA-Z][0-9a-zA-Z_]*`
</table>

Note: literals are parsed greedy. This means that for statements like `a -5`
      this will *not* parse as `a` `minus` `5` but instead as `a` `-5` which
      may be unexpected. A space must be inserted after the `-` if the first
      expression is desired.

## Attributes TODO ## {#attributes}

## Declarations TODO ## {#declarations}

TODO: This is a stub.

(Forward Reference) A name can denote a value, a type, a function, a variable, an import.

### Scoping ### {#scoping}

A declaration introduces a name, given by an identifier token.
Scoping is the set of rules determining where that name may be used, in relation to
the position of the declaration in the program.
If a name may be used at a particular point in the program, then we say it is <dfn dfn noexport>in scope</dfn>.

Issue: (dneto) also lifetime.

There are multiple levels of scoping depending on how and where things are
declared.

A declaration must not introduce a name when that name is already in scope at the start
of the declaration.
That is, shadow names are not allowed in [SHORTNAME].

### Identifier name spaces TODO ### {#namespace}

TODO: *Stub* Identifiers vs. attributes vs imports vs. ?
For example, an attribute may have the same name as an identifier.


# Types # {#types}

Note: For the syntax of declaring types in [SHORTNAME] please see the [[#grammar]].
TODO(dneto): This note is probably editorially obsolete.

Programs calculate values. Each value in [SHORTNAME] belongs to exactly one *type*.
A type is a set of (mathematical) values.

We distinguish between the concept of a type and the syntax in [SHORTNAME] to denote that type.
In many cases the spelling of a type in this document is the same as its [SHORTNAME] syntax.
The spelling is different for structure types, or types containing structures.

## Type Checking ## {#type-checking}

Type checking is the process of mapping terms in the [SHORTNAME] source language to [[#types]].

Generally, we start by determining types for the smallest [SHORTNAME] source phrases, and then build up
via combining rules.

If we can derive a type for the whole [SHORTNAME] source program via the type rules, then we say
the program is *well-typed*.  Otherwise there is a type error and is not a valid
[SHORTNAME] program.


Issue: (dneto) complete

### Explanation for those familiar with formal type checking ### {#type-check-preamble}

Much of it can be bottom-up, like usual.

The interesting bit is that the type of a pointer expression is either straightforward pointer
type itself, or the pointee type, depending on its [[#pointer-evaluation]] context:

* In Indexing, Assigning (LValue), and Copying contexts, the pointer expression denotes a pointer value.
* In a Parameter context:
 * If the parameter type matches the pointer expression's straightforward pointer type, then the expression denotes that pointer type.
 * Otherwise the pointer expression denotes a value of the pointee type, being the value loaded (at that time) from the referenced storage.
* In a Reading (RValue) context, the pointer expression denotes a value of the pointee type.

### How to read type-checking rules ### {#type-check-how-to-read}

A *type assertion* is a mapping from some [SHORTNAME] source expression to an [SHORTNAME] type.
When this specification has

> *e* : *T*

we are saying the [SHORTNAME] expression *e* is of type *T*.
In the type rules, the [SHORTNAME] source expression will often have placeholders in *italics* that
represent sub-expressions in the grammar.

In the type checking tables, each row represents a type deduction rule:
If the conditions in the precondition column are satisfied, then
the type assertion in the conclusion column is also satisfied.

For convenience, we will use the following shorthands:

<table class='data'>
  <tr><td>*Scalar*<td>[=scalar=] types: one of bool, i32, u32, f32
  <tr><td>*BoolVec*<td>[[#vector-types]] with bool component
  <tr><td>*Int*<td>i32 or u32
  <tr><td>*IntVec*<td>[[#vector-types]] with an *Int* component
  <tr><td>*Integral*<td>*Int* or [[#vector-types]] with an *Int* component
  <tr><td>*FloatVec*<td>[[#vector-types]] with f32 component
  <tr><td>*Floating*<td>f32 or *FloatVec*
  <tr><td>*Arity(T)*<td>number of components in [[#vector-types]] *T*
</table>



## Void Type ## {#void-type}

The <dfn noexport>void</dfn> type contains no values.

It is used where a type is required by the language but where no values are produced or consumed.
For example, it is used for the return type of a function which does not produce a value.

## Value Types ## {#value-types}

### Boolean Type ### {#bool-type}

The <dfn dfn noexport>`bool`</dfn> type contains the values true and false.

### Integer Types ### {#integer-types}

The <dfn dfn noexport>u32</dfn> type is the set of 32-bit unsigned integers.

The <dfn noexport>i32</dfn> type is the set of 32-bit signed integers.
It uses a two's complementation representation, with the sign bit in the most significant bit position.

### Floating Point Type ### {#floating-point-types}

The <dfn noexport>f32</dfn> type is the set of 32-bit floating point values of the IEEE 754 binary32 (single precision) format.
See [[#floating-point-evaluation]] for details.

### Scalar Types ### {#scalar-types}

The <dfn dfn noexport>scalar</dfn> types are [=bool=], [=i32=], [=u32=], and [=f32=].

The <dfn dfn noexport>numeric scalar</dfn> types are [=i32=], [=u32=], and [=f32=].

### Vector Types ### {#vector-types}
<table class='data'>
  <thead>
    <tr><td>Type<td>Description
  </thead>
  <tr><td>vec*N*<*T*><td>Vector of *N* elements of type *T*.
                          *N* must be in {2, 3, 4} and *T*
                          must be one of the [=scalar=] types.
                          We say *T* is the component type of the vector
</table>

A vector type is a <dfn dfn>numeric vector</dfn> type if its component type is a [=numeric scalar=].

<div class='example' heading='Vector'>
  <xmp highlight='rust'>
    vec2<f32>  # is a vector of two f32s.
  </xmp>
</div>

### Matrix Types ### {#matrix-types}
<table class='data'>
  <thead>
    <tr><td>Type<td>Description
  </thead>
  <tr><td>mat*N*x*M*<*T*><td>Matrix of *N* columns and *M* rows, where
                                *N* and *M* are both in {2, 3, 4}.
                                *T* must be *f32*.
</table>

<div class='example' heading='Matrix'>
  <xmp highlight='rust'>
    mat2x3<f32>  # is a 2 column, 3 row matrix of 32-bit floats.
  </xmp>
</div>

### Array Types ### {#array-types}
<table class='data'>
  <thead>
    <tr><td>Type<td>Description
  </thead>
  <tr><td>array<*E*,*N*><td>An *N*-element array of elements of type *E*.<br>
  <tr><td>array<*E*><td>A runtime-sized array of elements of type *E*,
                       also known as a runtime array.
                       These may only appear in specific contexts.<br>
</table>

Issue: (dneto): Complete description of `Array<E,N>`

Issue: (dneto): Runtime-sized array is only usable as the last element of a struct defining the contents of a storage buffer.

### Structure Types ### {#struct-types}
<table class='data'>
  <thead>
    <tr><td>Type<td>Description
  </thead>
  <tr><td>struct<*T1*,...,*Tn*><td>An ordered tuple of *N* members of types
                                    *T1* through *Tn*, with *N* being an
                                    integer greater than 0.
</table>

<div class='example' heading="Structure">
  <xmp highlight='rust'>
    struct Data {
      a : i32;
      b : vec2<f32>;
    }
  </xmp>
</div>

<pre class='def'>
struct_decl
  : struct_decoration_decl? STRUCT IDENT struct_body_decl

struct_decoration_decl
  : ATTR_LEFT struct_decoration ATTR_RIGHT

struct_decoration
  : BLOCK

struct_body_decl
  : BRACE_LEFT struct_member* BRACE_RIGHT

struct_member
  : struct_member_decoration_decl variable_ident_decl SEMICOLON

struct_member_decoration_decl
  :
  | ATTR_LEFT (struct_member_decoration COMMA)* struct_member_decoration ATTR_RIGHT

struct_member_decoration
  : OFFSET INT_LITERAL
</pre>

Note: Layout decorations are required if the struct is used in an SSBO, UBO or
           Push Constant.  Otherwise, the layout will be ignored.

Issue: (dneto): MatrixStride, RowMajor, ColMajor layout decorations are needed for matrices.

<div class='example' heading='Structure'>
  <xmp>
    struct my_struct {
      [[offset 0]] a : f32;
      [[offset 4]] b : vec4<f32>;
    };

                  OpName %my_struct "my_struct"
                  OpMemberName %my_struct 0 "a"
                  OpMemberDecorate %my_struct 0 Offset 0
                  OpMemberName %my_struct 1 "b"
                  OpMemberDecorate %my_struct 1 Offset 4
     %my_struct = OpTypeStruct %float %v4float

    type RTArr = [[stride 16]] array<vec4<f32>>;

    [[block]] struct S {
      [[offset 0]] a : f32;
      [[offset 4]] b : f32;
      [[offset 16]] data : RTArr;
    };
  </xmp>
</div>


## Memory TODO ## {#memory}

TODO: This section is a stub.

In [SHORTNAME], a value of [[#storable-types]] may be stored in memory, for later retrieval.

### Memory Locations TODO ### {#memory-locations}

TODO: *This is a stub*

Memory consists of distinct locations.

### Storable Types ### {#storable-types}

The following types are <dfn dfn noexport>storable</dfn>:

* [[#scalar-types]]
* [[#vector-types]]
* [[#matrix-types]]
* [[#array-types]] if its element type is storable.
* [[#struct-types]] if all its members are storable.

### Host-shareable Types ### {#host-shareable-types}

The following types are <dfn dfn noexport>host-shareable</dfn>:

* [=numeric scalar=] types
* [=numeric vector=] types
* [[#matrix-types]]
* [[#array-types]] if the array type has a stride attribute and its element type is host-shareable
* [[#struct-types]] if all its members are host-shareable

TODO: *This is a stub*: Collectively, the *stride* and *offset* attributes are called *layout attributes*.

### Storage Classes TODO ### {#storage-class}

<pre class='def'>
storage_class
  : INPUT
  | OUTPUT
  | UNIFORM
  | WORKGROUP
  | UNIFORM_CONSTANT
  | STORAGE_BUFFER
  | IMAGE
  | PRIVATE
  | FUNCTION
</pre>

<table class='data'>
  <thead>
    <tr><td>Name<td>SPIR-V Storage Class
  </thead>
  <tr><td>input<td>Input
  <tr><td>output<td>Output
  <tr><td>uniform<td>Uniform
  <tr><td>workgroup<td>Workgroup
  <tr><td>uniform_constant<td>UniformConstant
  <tr><td>storage_buffer<td>StorageBuffer
  <tr><td>image<td>Image
  <tr><td>private<td>Private
  <tr><td>function<td>Function
</table>


### Memory Layout Rules TODO ### {#memory-layout}

TODO: *The following is a stub*

Variables in certain storage classes must have host-shareable store type with fully elaborated memory layout.

The memory layout of a type is significant only when referring to a value in those storage classes.
This affects evaluation of a variable in one of those storage classes, or a pointer into one of those storage classes.

## Pointer Types TODO ## {#pointer-types}
<table class='data'>
  <thead>
    <tr><td>Type<td>Description
  </thead>
  <tr><td>ptr<*SC*,*T*><td>Pointer (or reference) to storage in [[#storage-class]] *SC*
                            which can hold a value of the [[#storable-types]] *T*.
                            Here, *T* is the known as the *pointee* type.
</table>

Note: We've described a SPIR-V logical pointer type.

Note: Pointers are not storable.

<div class='example' heading='Pointer'>
  <xmp highlight='rust'>
    ptr<storage_buffer, i32>
    ptr<private, array<i32, 12>>
  </xmp>
</div>

### Abstract Operations on Pointers TODO ### {#abstract-pointer-operations}

A pointer value *P* supports the following operations:

<table class='data'>
  <tr><td>P.Write(V)<td>Place a value V into the referenced storage.
               V’s type must match P’s pointee type.
  <tr><td>P.Read()<td>An evaluation yielding the value currently in the P’s
             referenced storage.  The result type is P's pointee type.
  <tr><td>P.Subaccess(K)<td>Valid for pointers with a composite pointee type where
                   *K* must evaluate to an integer between 0 and one
                   less than the number of components in *P*’s pointee type.
                   The subaccess evaluation yields a pointer to the storage for
                   the K’th component within P’s referenced storage,
                   using zero-based indexing. If P's storage class is SC, and
                   the K'th member of P's pointee type is of type T, then
                   the result type is `ptr<SC,T>`.
</table>

Note: Assignment of swizzled values is not permitted (SubaccessSwizzle).<br>
           e.g. `vec4<i32> v; v.xz = vec2<i32>(0, 1);` is not allowed.

### Pointer Evaluation TODO ### {#pointer-evaluation}

TODO: *This is a stub*: Using pointers in context. Disambiguating which abstract operation occurs based on context:
pointer semantics vs. dereferenced value semantics.

---

A pointer may appear in exactly the following contexts

<table class='data'>
  <tr><td>Indexing<td>
A subaccessing evaluation
* E.g. `a[12]`
    * If `a` is a pointer to an array, this evaluates to *a.Subaccess(12)*

* E.g. `s.foo`
    * If `s` is a pointer to a structure of type *S*, `k` is the index of the `foo` element of *S*, this evaluates to *s.Subaccess(k)*

  <tr><td>Assigning (L-Value)<td>
On the left hand side of an assignment operation, and the right hand side
matches the pointee type of the pointer.
* E.g. `v = 12;` assuming prior declaration `var v : i32`

  <tr><td>Copying<td>
On the right hand side of a const-declaration, and the type of the
const-declaration matches the pointer type.
* E.g. `const v2 : ptr<private,i32> = v;`  assuming prior declaration
        `var<private> v:i32`

  <tr><td>Parameter<td>
Used in a function call, where the function’s parameter type matches the
pointer type.

  <tr><td>Reading (R-Value)<td>
Any other context.  Evaluates to *P.Read()*, yielding a value of *P*’s pointee
type.
</table>

## Texture Types TODO ## {#texture-types}

### Sampled Texture Types ### {#sampled-texture-type}

<pre class='def'>
`texture_sampled_1d<type>`
  %1 = OpTypeImage %type 1D 0 0 0 1 Unknown

`texture_sampled_1d_array<type>`
  %1 = OpTypeImage %type 1D 0 1 0 1 Unknown

`texture_sampled_2d<type>`
  %1 = OpTypeImage %type 2D 0 0 0 1 Unknown

`texture_sampled_2d_array<type>`
  %1 = OpTypeImage %type 2D 0 1 0 1 Unknown

`texture_sampled_3d<type>`
  %1 = OpTypeImage %type 3D 0 0 0 1 Unknown

`texture_sampled_2d_ms<type>`
  %1 = OpTypeImage %type 2D 0 0 1 1 Unknown

`texture_sampled_2d_ms_array<type>`
  %1 = OpTypeImage %type 2D 0 1 1 1 Unknown

`texture_sampled_cube<type>`
  %1 = OpTypeImage %type Cube 0 0 0 1 Unknown

`texture_sampled_cube_array<type>`
  %1 = OpTypeImage %type Cube 0 1 0 1 Unknown
</pre>
* type must be `f32`, `i32` or `u32`
* The parameterized type for the images is the type after conversion from sampling.
    E.g. you can have an image with texels with 8bit unorm components, but when you sample
    them you get a 32-bit float result (or vec-of-f32).

### Read-only Storage Texture Types ### {#texture-ro}
<pre class='def'>
`texture_ro_1d<type, image_storage_type>`
  %1 = OpTypeImage %type 1D 0 0 0 2 image_storage_type

`texture_ro_1d_array<type, image_storage_type>`
  %1 = OpTypeImage %type 1D 0 1 0 2 image_storage_type

`texture_ro_2d<type, image_storage_type>`
  %1 = OpTypeImage %type 2D 0 0 0 2 image_storage_type

`texture_ro_2d_array<type, image_storage_type>`
  %1 = OpTypeImage %type 2D 0 1 0 2 image_storage_type

`texture_ro_3d<type, image_storage_type>`
  %1 = OpTypeImage %type 3D 0 0 0 2 image_storage_type
</pre>
* type must be `f32`, `i32` or `u32`
* The parameterized type for the images is the type after conversion from reading.
    E.g. you can have an image with texels with 8bit unorm components, but when you read
    them you get a 32-bit float result (or vec-of-f32).

### Write-only Storage Texture Types ### {#texture-wo}
<pre class='def'>
`texture_wo_1d<image_storage_type>`
  %1 = OpTypeImage %void 1D 0 0 0 2 image_storage_type

`texture_wo_1d_array<image_storage_type>`
  %1 = OpTypeImage %void 1D 0 1 0 2 image_storage_type

`texture_wo_2d<image_storage_type>`
  %1 = OpTypeImage %void 2D 0 0 0 2 image_storage_type

`texture_wo_2d_array<image_storage_type>`
  %1 = OpTypeImage %void 2D 0 1 0 2 image_storage_type

`texture_wo_3d<image_storage_type>`
  %1 = OpTypeImage %void 3D 0 0 0 2 image_storage_type
</pre>

### Depth Texture Types ### {#texture-depth}
<pre class='def'>
`texture_depth_2d`
  %1 = OpTypeImage %f32 2D 1 0 0 1 Unknown

`texture_depth_2d_array`
  %1 = OpTypeImage %f32 2D 1 1 0 1 Unknown

`texture_depth_cube`
  %1 = OpTypeImage %f32 Cube 1 0 0 1 Unknown

`texture_depth_cube_array`
  %1 = OpTypeImage %f32 Cube 1 1 0 1 Unknown
</pre>

### Sampler Type ### {#sampler-type}
<pre class='def'>
sampler
  OpTypeSampler

sampler_comparison
  OpTypeSampler
</pre>

### Texture Types Grammar ### {#texture-types-grammar}

<pre class='def'>
sampler_or_texture_decl
  : VAR variable_storage_decoration? IDENT COLON texture_sampler_types

texture_sampler_types
  : sampler_type
  | depth_texture_type
  | sampled_texture_type LESS_THAN type_decl GREATER_THAN
  | storage_texture_type LESS_THAN image_storage_type GREATER_THAN

sampler_type
  : SAMPLER
  | SAMPLER_COMPARISON

sampled_texture_type
  : TEXTURE_SAMPLED_1D
  | TEXTURE_SAMPLED_1D_ARRAY
  | TEXTURE_SAMPLED_2D
  | TEXTURE_SAMPLED_2D_ARRAY
  | TEXTURE_SAMPLED_2D_MS
  | TEXTURE_SAMPLED_2D_MS_ARRAY
  | TEXTURE_SAMPLED_3D
  | TEXTURE_SAMPLED_CUBE
  | TEXTURE_SAMPLED_CUBE_ARRAY

storage_texture_type
  : TEXTURE_RO_1D
  | TEXTURE_RO_1D_ARRAY
  | TEXTURE_RO_2D
  | TEXTURE_RO_2D_ARRAY
  | TEXTURE_RO_3D
  | TEXTURE_WO_1D
  | TEXTURE_WO_1D_ARRAY
  | TEXTURE_WO_2D
  | TEXTURE_WO_2D_ARRAY
  | TEXTURE_WO_3D

depth_texture_type
  : TEXTURE_DEPTH_2D
  | TEXTURE_DEPTH_2D_ARRAY
  | TEXTURE_DEPTH_CUBE
  | TEXTURE_DEPTH_CUBE_ARRAY

image_storage_type
  : R8UNORM
     R8  -- Capability: StorageImageExtendedFormats
  | R8SNORM
     R8Snorm  -- Capability: StorageImageExtendedFormats
  | R8UINT
     R8ui  -- Capability: StorageImageExtendedFormats
  | R8SINT
     R8i  -- Capability: StorageImageExtendedFormats
  | R16UINT
     R16ui  -- Capability: StorageImageExtendedFormats
  | R16SINT
     R16i  -- Capability: StorageImageExtendedFormats
  | R16FLOAT
     R16f  -- Capability: StorageImageExtendedFormats
  | RG8UNORM
     Rg8  -- Capability: StorageImageExtendedFormats
  | RG8SNORM
     Rg8Snorm  -- Capability: StorageImageExtendedFormats
  | RG8UINT
     Rg8ui  -- Capability: StorageImageExtendedFormats
  | RG8SINT
     Rg8i  -- Capability: StorageImageExtendedFormats
  | R32UINT
     R32ui
  | R32SINT
     R32i
  | R32FLOAT
     R32f
  | RG16UINT
     Rg16ui  -- Capability: StorageImageExtendedFormats
  | RG16SINT
     Rg16i  -- Capability: StorageImageExtendedFormats
  | RG16FLOAT
     Rg16f  -- Capability: StorageImageExtendedFormats
  | RGBA8UNORM
     Rgba8
  | RGBA8UNORM-SRGB
     ???
  | RGBA8SNORM
     Rgba8Snorm
  | RGBA8UINT
     Rgba8ui
  | RGBA8SINT
     Rgba8i
  | BGRA8UNORM
     Rgba8  ???
  | BGRA8UNORM-SRGB
     ???
  | RGB10A2UNORM
     Rgb10A2  -- Capability: StorageImageExtendedFormats
  | RG11B10FLOAT
     R11fG11fB10f  -- Capability: StorageImageExtendedFormats
  | RG32UINT
     Rg32ui  -- Capability: StorageImageExtendedFormats
  | RG32SINT
     Rg32i  -- Capability: StorageImageExtendedFormats
  | RG32FLOAT
     Rg32f  -- Capability: StorageImageExtendedFormats
  | RGBA16UINT
     Rgba16ui
  | RGBA16SINT
     Rgba16i
  | RGBA16FLOAT
     Rgba16f
  | RGBA32UINT
     Rgba32ui
  | RGBA32SINT
     Rgba32i
  | RGBA32FLOAT
     Rgba32f

</pre>

## Type Aliases TODO ## {#type-aliases}

<pre class='def'>
type_alias
  : TYPE IDENT EQUAL type_decl
</pre>

<div class='example' heading='Type Alias'>
  <xmp>
    type Arr = array<i32, 5>;

    type RTArr = [[stride 16]] array<vec4<f32>>;
  </xmp>
</div>

## Type Declaration Grammar ## {#type-declarations}

<pre class='def'>
type_decl
  : IDENT
  | BOOL
  | FLOAT32
  | INT32
  | UINT32
  | VEC2 LESS_THAN type_decl GREATER_THAN
  | VEC3 LESS_THAN type_decl GREATER_THAN
  | VEC4 LESS_THAN type_decl GREATER_THAN
  | PTR LESS_THAN storage_class, type_decl GREATER_THAN
  | array_decoration_list? ARRAY LESS_THAN type_decl COMMA INT_LITERAL GREATER_THAN
  | array_decoration_list? ARRAY LESS_THAN type_decl GREATER_THAN
  | MAT2x2 LESS_THAN type_decl GREATER_THAN
  | MAT2x3 LESS_THAN type_decl GREATER_THAN
  | MAT2x4 LESS_THAN type_decl GREATER_THAN
  | MAT3x2 LESS_THAN type_decl GREATER_THAN
  | MAT3x3 LESS_THAN type_decl GREATER_THAN
  | MAT3x4 LESS_THAN type_decl GREATER_THAN
  | MAT4x2 LESS_THAN type_decl GREATER_THAN
  | MAT4x3 LESS_THAN type_decl GREATER_THAN
  | MAT4x4 LESS_THAN type_decl GREATER_THAN
</pre>

When the type declaration is an identifer, then the expression must be in scope of a
declaration of the identifier as a type alias or structure type.

<pre class='def'>
array_decoration_list
  : ATTR_LEFT (array_decoration COMMA)* array_decoration ATTR_RIGHT

array_decoration
  : STRIDE INT_LITERAL
</pre>

<div class='example' heading="Type Declarations">
  <xmp>
    identifier
      Allows to specify types created by the type command

    bool
       %1 = OpTypeBool

    f32
       %2 = OpTypeFloat 32

    i32
       %3 = OpTypeInt 32 1

    u32
       %4 = OpTypeInt 32 0

    vec2<f32>
        %7 = OpTypeVector %float 2

    array<f32, 4>
       %uint_4 = OpConstant %uint 4
            %9 = OpTypeArray %float %uint_4

    [[stride 32]] array<f32, 4>
                 OpDecorate %9 ArrayStride 32
       %uint_4 = OpConstant %uint 4
            %9 = OpTypeArray %float %uint_4

    array<f32>
       %rtarr = OpTypeRuntimeArray %float

    mat2x3<f32>
       %vec = OpTypeVector %float 3
         %6 = OpTypeMatrix %vec 2
  </xmp>
</div>


# Variable and const # {#variables}

TODO: *Stub* (describe what a constant is): A constant is a name for a value, declared via a `const` declaration.

A <dfn dfn noexport>variable</dfn> is a named reference to storage that can contain a value of a
particular storable type.

Two types are associated with a variable: its *store type* (the type of value
that may be placed in the referenced storage) and its *reference type* (the type
of the variable itself).  If a variable has store type *T* and storage class *S*,
then its reference type is pointer-to-*T*-in-*S*.

A <dfn dfn noexport>variable declaration</dfn>:

* Determines the variable’s name, storage class, and store type (and hence its reference type)
* Ensures the execution environment allocates storage for a value of the store type, for the lifetime of the variable.
* Optionally have an *initializer* expression, if the variable is in the `Private`, `Function`, or `Output` [[#storage-class]].
    If present, the intiailizer's type must match the store type of the variable.

<pre class='def'>
variable_statement
  : variable_decl
  | variable_decl EQUAL short_circuit_or_expression
  | CONST variable_ident_decl EQUAL short_circuit_or_expression

variable_decl
  : VAR variable_storage_decoration? variable_ident_decl

variable_ident_decl
  : IDENT COLON type_decl

variable_storage_decoration:
  : LESS_THAN storage_class GREATER_THAN
</pre>

Two variables with overlapping lifetimes must not have overlapping storage.

When a variable is created, its storage contains an initial value as follows:

* For variables in the `Private`, `Function`, or `Output` storage classes:
    * The zero value for the store type, if the variable declaration has no initializer.
    * Otherwise, it is the result of evaluating the initializer expression at that point in the program execution.
* For variables in other storage classes, the execution environment provides the initial value.

<div class='example' header='Variable initial values'>
  Consider the following snippet of WGSL:
  <xmp highlight='rust'>
    var i: i32;         # Initial value is 0.  Not recommended style.
    loop {
      var twice: i32 = 2 * i;   # Re-evaluated each iteration.
      i = i + 1;
      break if (i == 5);
    }
  </xmp>
  The loop body will execute five times.
  Variable `i` will take on values 0, 1, 2, 3, 4, 5, and variable `twice` will take on values 0, 2, 4, 6, 8.
</div>

<div class='example'>
  Consider the following snippet of WGSL:
  <xmp highlight='rust'>
    var x : f32 = 1.0;
    const y = x * x + x + 1;
  </xmp>
  Because `x` is a variable, all accesses to it turn into load and store operations.
  If this snippet was compiled to SPIR-V, it would be represented as
  <xmp highlight='asm'>
    %temp_1 = OpLoad %float %x
    %temp_2 = OpLoad %float %x
    %temp_3 = OpFMul %float %temp_1 %temp_2
    %temp_4 = OpLoad %float %x
    %temp_5 = OpFAdd %float %temp_3 %temp_4
    %y      = OpFAdd %float %temp_5 %one
  </xmp>
  However, it is expected that either the browser or the driver optimizes this intermediate representation
  such that the redundant loads are eliminated.
</div>

## Module Scope Variables ## {#module-scope-variables}

A variable or constant declared outside a function is at *module scope*.
The name is available for use immediately after its declaration statement, until the end
of the program.

<pre class='def'>
global_variable_decl
  : variable_decoration_list? variable_decl
  | variable_decoration_list? sampler_or_texture_decl
  | variable_decoration_list? variable_decl EQUAL const_expr

global_constant_decl
  : CONST variable_ident_decl EQUAL const_expr

variable_decoration_list
  : ATTR_LEFT (variable_decoration COMMA)* variable_decoration ATTR_RIGHT

variable_decoration
  : LOCATION INT_LITERAL
  | BUILTIN IDENT
  | BINDING INT_LITERAL
  | SET INT_LITERAL
</pre>

<div class='example' heading="Variable Decorations">
  <xmp>
    [[location 2]]
       OpDecorate %gl_FragColor Location 2

    [[binding 3, set 4]]
       OpDecorate %gl_FragColor Binding 3
       OpDecorate %gl_FragColor DescriptorSet 4
  </xmp>
</div>

See [[#builtin-variables]] for the decorations for specifying built-in variables.

## Module Constants ## {#module-constants}

A *module constant* declares a name for a value, outside of all function declarations.
The name is available for use after the end of the declaration,
until the end of the [SHORTNAME] program.

When the declaration has no attributes, an initializer expression must be present,
and the name denotes the value of that expression.

<div class='example' heading='Module constants'>
  <xmp>
    const golden : f32 = 1.61803398875;       # The golden ratio
    const e2 : vec3<i32> = vec3<i32>(0,1,0);  # The second unit vector for three dimensions.
  </xmp>
</div>

When the declaration uses the `constant_id` attribute,
the constant is *pipeline-overridable*. In this case:

  * The type must one of the [=scalar=] types.
  * The initializer expression is optional.
  * The attribute's literal operand is known as the *pipeline constant ID*,
    and must be a non-negative integer value representable in 32 bits.
  * Pipeline constant IDs must be unique within the [SHORTNAME] program: Two module constants
    must not use the same pipeline constant ID.
  * The application can specify its own value for the name at pipeline-creation time.
    The pipeline creation API accepts a mapping from the pipeline constant ID
    to a value of the constant's type.
    If the mapping has an entry for the ID, the value in the mapping is used.
    Otherwise, the initializer expression must be present, and its value is used.

Issue(dneto): What happens is the application supplies a constant ID that is not in the program?
Proposal: pipeline creation fails with an error.

<div class='example' heading='Module constants, pipeline-overrideable'>
  <xmp>
    [[constant_id 0]]    const has_point_light : bool = true;      # Algorithmic control
    [[constant_id 1200]] const specular_param : f32 = 2.3;         # Numeric control
    [[constant_id 1300]] const gain : f32;                         # Must be overridden
  </xmp>
</div>

When a variable or feature is used within control flow that depends on the
value of a constant, then that variable or feature is considered to be used by the
program.
This is true regardless of the value of the constant, whether that value
is the one from the constant's declaration or from a pipeline override.

<pre class='def'>
global_constant_decl
  : global_const_decoration_list? CONST variable_ident_decl global_const_initializer?

global_const_decoration_list
  : ATTR_LEFT global_const_decoration ATTR_RIGHT

global_const_decoration
  : CONSTANT_ID INT_LITERAL

global_const_initializer
  : EQUAL const_expr

const_expr
  : type_decl PAREN_LEFT (const_expr COMMA)* const_expr PAREN_RIGHT
  | const_literal
</pre>

<div class='example' heading='Constants'>
  <xmp>
    -1
       %a = OpConstant %int -1

    2
       %b = OpConstant %uint 2

    3.2
       %c = OpConstant %float 3.2

    true
        %d = OpConstantTrue

    false
        %e = OpConstant False

    vec4<f32>(1.2, 2.3, 3.4, 2.3)
        %f0 = OpConstant %float 1.2
        %f1 = OpConstant %float 2.3
        %f2 = OpConstant %float 3.4
         %f = OpConstantComposite %v4float %f0 %f1 %f2 %f1
  </xmp>
</div>

Issue(dneto): The WebGPU pipeline creation API must specify how API-supplied values are mapped to
shader scalar values.  For booleans, I suggest using a 32-bit integer, where only 0 maps to `false`.
If [SHORTNAME] gains non-32-bit numeric scalars, I recommend overridable constants continue being 32-bit
numeric types.

## Function Scope Variables ## {#function-scope-variables}

A variable or constant declared in a declaration statement in a function body is in *function scope*.
The name is available for use immedately after its declaration statement,
and until the end of the brace-delimited list of statements immediately enclosing the declaration.

A variable or constant declared in the first clause of a `for` statement is available for use in the second
and third clauses and in the body of the `for` statement.


## Never-alias assumption TODO ## {#never-alias-assumption}

# Expressions TODO # {#expressions}

## Literal Expressions TODO ## {#literal-expressions}

<table class='data'>
  <caption>Scalar literal type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td><td>`true` : bool<td>OpConstantTrue %bool
  <tr><td><td>`false` : bool<td>OpConstantFalse %bool
  <tr><td><td>*INT_LITERAL* : i32<td>OpConstant %int *literal*
  <tr><td><td>*UINT_LITERAL* : u32<td>OpConstant %uint *literal*
  <tr><td><td>*FLOAT_LITERAL* : f32<td>OpConstant %float *literal*
</table>

## Type Constructor Expressions TODO ## {#type-constructor-expr}

<table class='data'>
  <caption>Scalar constructor type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e* : bool<td>`bool(e)` : bool<td>Pass-through (OpCopyObject)
  <tr><td>*e* : i32<td>`i32(e)` : i32<td>Pass-through (OpCopyObject)
  <tr><td>*e* : u32<td>`u32(e)` : u32<td>Pass-through (OpCopyObject)
  <tr><td>*e* : f32<td>`f32(e)` : f32<td>Pass-through (OpCopyObject)
</table>

<table class='data'>
  <caption>Vector constructor type rules, where *T* is a scalar type</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>*e1* : *T*<br>
        *e2* : *T*
    <td>`vec2<T>(e1,e2)` : vec2<*T*>
    <td>OpCompositeConstruct
  <tr>
    <td>*e1* : *T*<br>
        *e2* : *T*<br>
        *e3* : *T*
    <td>`vec3<T>(e1,e2,e3)` : vec3<*T*>
    <td>OpCompositeConstruct
  <tr>
    <td>*e1* : *T*<br>
        *e2* : *T*<br>
        *e3* : *T*<br>
        *e4* : *T*
    <td>`vec4<T>(e1,e2,e3,e4)` : vec4<*T*>
    <td>OpCompositeConstruct
  <tr>
    <td>*e1* : *T*<br>
        *e2* : vec2<*T*>
    <td>`vec3<T>(e1,e2)` : vec3<*T*><br>
        `vec3<T>(e2,e1)` : vec3<*T*>
    <td>OpCompositeConstruct
  <tr>
    <td>*e1* : *T*<br>
        *e2* : *T*<br>
        *e3* : vec2<*T*>
    <td>`vec4<T>(e1,e2,e3)` : vec4<*T*><br>
        `vec4<T>(e1,e3,e2)` : vec4<*T*><br>
        `vec4<T>(e3,e1,e2)` : vec4<*T*>
    <td>OpCompositeConstruct
  <tr>
    <td>*e1* : vec2<*T*><br>
        *e2* : vec2<*T*>
    <td>`vec4<T>(e1,e2)` : vec4<*T*>
    <td>OpCompositeConstruct
  <tr>
    <td>*e1* : *T*<br>
        *e2* : vec3<*T*>
    <td>`vec4<T>(e1,e2)` : vec4<*T*><br>
        `vec4<T>(e2,e1)` : vec4<*T*>
    <td>OpCompositeConstruct
</table>

<table class='data'>
  <caption>Matrix constructor type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>*e1* : vec2<f32><br>
        *e2* : vec2<f32><br>
        *e3* : vec2<f32><br>
        *e4* : vec2<f32>
    <td>`mat2x2<f32>(e1,e2)` : mat2x2<f32><br>
        `mat3x2<f32>(e1,e2,e3)` : mat3x2<f32><br>
        `mat4x2<f32>(e1,e2,e3,e4)` : mat4x2<f32>
    <td>Column by column construction.<br>
        OpCompositeConstruct
  <tr>
    <td>*e1* : vec3<f32><br>
        *e2* : vec3<f32><br>
        *e3* : vec3<f32><br>
        *e4* : vec3<f32>
    <td>`mat2x3<f32>(e1,e2)` : mat2x3<f32><br>
        `mat3x3<f32>(e1,e2,e3)` : mat3x3<f32><br>
        `mat4x3<f32>(e1,e2,e3,e4)` : mat4x3<f32>
    <td>Column by column construction.<br>
        OpCompositeConstruct
  <tr>
    <td>*e1* : vec4<f32><br>
        *e2* : vec4<f32><br>
        *e3* : vec4<f32><br>
        *e4* : vec4<f32>
    <td>`mat2x4<f32>(e1,e2)` : mat2x4<f32><br>
        `mat3x4<f32>(e1,e2,e3)` : mat3x4<f32><br>
        `mat4x4<f32>(e1,e2,e3,e4)` : mat4x4<f32>
    <td>Column by column construction.<br>
        OpCompositeConstruct
</table>

<table class='data'>
  <caption>Array constructor type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>*e1* : *T*<br>
        ...<br>
        *eN* : *T*<br>
    <td>`array<`*T*,*N*`>(e1,...,eN)` : array<*T*, *N*>
    <td>Construction of an array from elements
</table>
TODO: Should this only work for storable sized arrays?  https://github.com/gpuweb/gpuweb/issues/982

<table class='data'>
  <caption>Structure constructor type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>*e1* : *T1*<br>
        ...<br>
        *eN* : *TN*<br>
        *T1* is storable<br>
        ...<br>
        *TN* is storable<br>
        S is a structure type with members having types *T1* ... *TN*.<br>
        The expression is in the scope of declaration of S.
    <td>`S(e1,...,eN)` : S
    <td>Construction of a structure from members
  <tr>
</table>


## Zero Value Expressions ## {#zero-value-expr}

Each storable type *T* has a unique *zero value*, written in WGSL as the type followed by an empty pair of parentheses: *T* `()`.

Issue: We should exclude being able to write the zero value for an runtime-sized array. https://github.com/gpuweb/gpuweb/issues/981

The zero values are as follows:

* `bool()` is `false`
* `i32()` is 0
* `u32()` is 0
* `f32()` is 0.0
* The zero value for an *N*-element vector of type *T* is the *N*-element vector of the zero value for *T*.
* The zero value for an *N*-column *M*-row matrix of `f32` is the matrix of those dimensions filled with 0.0 entries.
* The zero value for an *N*-element array with storable element type *E* is an array of *N* elements of the zero value for *E*.
* The zero value for a storable structure type *S* is the structure value *S* with zero-valued members.

<table class='data'>
  <caption>Scalar zero value type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td><td>`bool()` : bool<td>false<br>Zero value (OpConstantNull for bool)
  <tr><td><td>`i32()` : i32<td>0<br>Zero value (OpConstantNull for i32)
  <tr><td><td>`u32()` : u32<td>0u<br>Zero value (OpConstantNull for u32)
  <tr><td><td>`f32()` : f32<td>0.0<br>Zero value (OpConstantNull for f32)
</table>

<table class='data'>
  <caption>Vector zero type rules, where *T* is a scalar type</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>
    <td>`vec2<T>()` : vec2<*T*>
    <td>Zero value (OpConstantNull)
  <tr>
  <tr>
    <td>
    <td>`vec3<T>()` : vec3<*T*>
    <td>Zero value (OpConstantNull)
  <tr>
  <tr>
    <td>
    <td>`vec4<T>()` : vec4<*T*>
    <td>Zero value (OpConstantNull)
  <tr>
</table>


<div class='example' heading="Zero-valued vectors">
  <xmp highlight='rust'>
    vec2<f32>()                 # The zero-valued vector of two f32 elements.
    vec2<f32>(0.0, 0.0)         # The same value, written explicitly.

    vec3<i32>()                 # The zero-valued vector of four i32 elements.
    vec3<i32>(0, 0, 0)          # The same value, written explicitly.
  </xmp>
</div>

<table class='data'>
  <caption>Matrix zero type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>
    <td>`mat2x2<f32>()` : mat2x2<f32><br>
        `mat3x2<f32>()` : mat3x2<f32><br>
        `mat4x2<f32>()` : mat4x2<f32>
    <td>Zero value (OpConstantNull)
  <tr>
  <tr>
    <td>
    <td>`mat2x3<f32>()` : mat2x3<f32><br>
        `mat3x3<f32>()` : mat3x3<f32><br>
        `mat4x3<f32>()` : mat4x3<f32>
    <td>Zero value (OpConstantNull)
  <tr>
  <tr>
    <td>
    <td>`mat2x4<f32>()` : mat2x4<f32><br>
        `mat3x4<f32>()` : mat3x4<f32><br>
        `mat4x4<f32>()` : mat4x4<f32>
    <td>Zero value (OpConstantNull)
</table>

<table class='data'>
  <caption>Array zero type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>*T* is storable
    <td>`array<`*T*,*N*`>()` : array<*T*, *N*>
    <td>Zero-valued array (OpConstantNull)
</table>

<div class='example' heading="Zero-valued arrays">
  <xmp highlight='rust'>
    array<bool,2>()               # The zero-valued array of two booleans.
    array<bool,2>(false, false)   # The same value, written explicitly.
  </xmp>
</div>

<table class='data'>
  <caption>Structure zero type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr>
    <td>`S` is a storable structure type.<br>
         The expression is in the scope of declaration of S.
    <td>`S()` : S
    <td>Zero-valued structure: a structure of type S where each member is the zero value for its member type.
<br>
 (OpConstantNull)
  <tr>
</table>

<div class='example' heading="Zero-valued structures">
  <xmp highlight='rust'>
    struct Student {
      grade : i32;
      GPA : f32;
      attendance : array<bool,4>;
    };

    # The zero value for Student
    Student()

    # The same value, written explicitly.
    Student(0, 0.0, array<bool,4>(false,false,false,false))

    # The same value, written with zero-valued members.
    Student(i32(), f32(), array<bool,4>())
  </xmp>
</div>


## Conversion Expressions TODO ## {#conversion-expr}

<table class='data'>
  <caption>Scalar conversion type rules</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e* : u32<td>`i32(e)` : i32<td>Reinterpretation of bits (OpBitcast)
  <tr><td>*e* : f32<td>`i32(e)` : i32<td>Value conversion, including invalid cases (OpConvertFToS)
  <tr><td>*e* : i32<td>`u32(e)` : u32<td>Reinterpretation of bits (OpBitcast)
  <tr><td>*e* : f32<td>`u32(e)` : u32<td>Value conversion, including invalid cases (OpConvertFToU)
  <tr><td>*e* : i32<td>`f32(e)` : f32<td>Value conversion, including invalid cases (OpConvertSToF)
  <tr><td>*e* : u32<td>`f32(e)` : f32<td>Value conversion, including invalid cases (OpConvertUToF)
</table>

TODO: vector conversions

## Composite Value Expressions TODO ## {#composite-value-expr}

### Vector Access Expression ### {#vector-access-expr}

Accessing members of a vector can be done either using array subscripting (e.g. `a[2]`) or using a sequence of convenience names, each mapping to an element of the source vector.

<ul>
  <li>The colour set of convenience names: `r`, `g`, `b`, `a` for vector elements 0, 1, 2, and 3 respectively.
  <li>The dimensional set of convenience names: `x`, `y`, `z`, `w` for vector elements 0, 1, 2, and 3, respectively.
</ul>

The convenience names are accessed using the `.` notation. (e.g. `color.bgra`).

NOTE: the convenience letterings can not be mixed. (i.e. you can not use `rybw`).

Using a convenience letter, or array subscript, which accesses an element past the end of the vector is an error.

The convenience letterings can be applied in any order, including duplicating letters as needed. You can provide 1 to 4 letters when extracing components from a vector. Providing more then 4 letters is an error.

The result type depends on the number of letters provided. Assuming a `vec4<f32>`
<table>
  <thead>
    <tr><td>Accessor<td>Result type
  </thead>
  <tr><td>r<td>`f32`
  <tr><td>rg<td>`vec2<f32>`
  <tr><td>rgb<td>`vec3<f32>`
  <tr><td>rgba<td>`vec4<f32>`
</table>

<div class='example'>
  <xmp highlight='rust'>
    var a : vec3<f32> = vec3<f32>(1., 2., 3.);
    var b : f32 = a.y;          # b = 2.0
    var c : vec2<f32> = a.bb;   # c = (3.0, 3.0)
    var d : vec3<f32> = a.zyx;  # d = (3.0, 2.0, 1.0)
    var e : f32 = a[1];         # e = 2.0
  </xmp>
</div>

TODO: Type rules for vector access

### Matrix Access Expression TODO ### {#matrix-access-expr}

### Array Access Expression TODO ### {#array-access-expr}

### Structure Access Expression TODO ### {#struct-access-expr}

## Logical Expressions TODO ## {#logical-expr}
<table class='data'>
  <caption>Unary logical operations</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e* : bool<td>`!e` : *bool*<td>OpLogicalNot
</table>

<table class='data'>
  <caption>Binary logical expressions</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : bool<br>*e2* : bool<td>`e1 || e2` : bool<td>
    Short-circuiting "or". Yields `true` if either `e1` or `e2` are true; evaluates `e2` only if `e1` is false.
  <tr><td>*e1* : bool<br>*e2* : bool<td>`e1 && e2` : bool<td>
    Short-circuiting "and". Yields `true` if both `e1` and `e2` are true; evaluates `e2` only if `e1` is true.
  <tr><td>*e1* : bool<br>*e2* : bool<td>`e1 | e2` : bool<td>
    Logical "or". Evaluates both `e1` and `e2`; yields `true` if either are `true`.
  <tr><td>*e1* : bool<br>*e2* : bool<td>`e1 & e2` : bool<td>
    Logical "and". Evaluates both `e1` and `e2`; yields `true` if both are `true`.
  <tr><td>*e1* : *T*<br>*e2* : *T*<br>*T* is *BoolVec*<td>`e1 | e2` : *T*<td>Component-wise logical "or"
  <tr><td>*e1* : *T*<br>*e2* : *T*<br>*T* is *BoolVec*<td>`e1 & e2` : *T*<td>Component-wise logical "and"
</table>


## Arithmetic Expressions TODO ## {#arithemtic-expr}

<table class='data'>
  <caption>Unary arithmetic expressions</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e* : *T*, *T* is *Integral*<td>`-e` : *T*<td>OpSNegate
  <tr><td>*e* : *T*, *T* is *Floating*<td>`-e` : *T*<td>OpFNegate
</table>

<table class='data'>
  <caption>Binary arithmetic expressions over scalars</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : u32<br> *e2* : u32<td class="nowrap">`e1 + e2` : u32<td>Integer addition, modulo 2<sup>32</sup> (OpIAdd)
  <tr><td>*e1* : i32<br> *e2* : i32<td>`e1 + e2` : i32<td>Integer addition, modulo 2<sup>32</sup> (OpIAdd)
  <tr><td>*e1* : f32<br> *e2* : f32<td>`e1 + e2` : f32<td>Floating point addition (OpFAdd)
  <tr><td>*e1* : u32<br> *e2* : u32<td>`e1 - e2` : u32<td>Integer subtraction, modulo 2<sup>32</sup> (OpISub)
  <tr><td>*e1* : i32<br> *e2* : i32<td>`e1 - e2` : i32<td>Integer subtraction, modulo 2<sup>32</sup> (OpISub)
  <tr><td>*e1* : f32<br> *e2* : f32<td>`e1 - e2` : f32<td>Floating point subtraction (OpFSub)
  <tr><td>*e1* : u32<br> *e2* : u32<td>`e1 * e2` : u32<td>Integer multiplication, modulo 2<sup>32</sup> (OpIMul)
  <tr><td>*e1* : i32<br> *e2* : i32<td>`e1 * e2` : i32<td>Integer multiplication, modulo 2<sup>32</sup> (OpIMul)
  <tr><td>*e1* : f32<br> *e2* : f32<td>`e1 * e2` : f32<td>Floating point multiplication (OpFMul)
  <tr><td>*e1* : u32<br> *e2* : u32<td>`e1 / e2` : u32<td>Unsigned integer division (OpUDiv)
  <tr><td>*e1* : i32<br> *e2* : i32<td>`e1 / e2` : i32<td>Signed integer division (OpSDiv)
  <tr><td>*e1* : f32<br> *e2* : f32<td>`e1 / e2` : f32<td>Floating point division (OpFAdd)
  <tr><td>*e1* : u32<br> *e2* : u32<td>`e1 % e2` : u32<td>Unsigned integer modulus (OpUMod)
  <tr><td>*e1* : i32<br> *e2* : i32<td>`e1 % e2` : i32<td>Signed integer remainder, where sign of non-zero result matches sign of *e2* (OpSMod)
  <tr><td>*e1* : f32<br> *e2* : f32<td>`e1 % e2` : f32<td>Floating point modulus, where sign of non-zero result matches sign of *e2* (OpFMod)
</table>

<table class='data'>
  <caption>Binary arithmetic expressions over vectors</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec*<td class="nowrap">`e1 + e2` : *T*<td>Component-wise integer addition (OpIAdd)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *FloatVec*<td class="nowrap">`e1 + e2` : *T*<td>Component-wise floating point addition (OpIAdd)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec*<td class="nowrap">`e1 - e2` : *T*<td>Component-wise integer subtraction (OpISub)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *FloatVec*<td>`e1 - e2` : *T*<td>Component-wise floating point subtraction (OpISub)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec*<td>`e1 * e2` : *T*<td>Component-wise integer multiplication (OpIMul)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *FloatVec*<td>`e1 * e2` : *T*<td>Component-wise floating point multiplication (OpIMul)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec* with unsigned component<td>`e1 / e2` : *T*<td>Component-wise unsigned integer division (OpUDiv)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec* with signed component<td>`e1 / e2` : *T*<td>Component-wise signed integer division (OpSDiv)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *FloatVec*<td>`e1 / e2` : *T*<td>Component-wise floating point division (OpFDiv)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec* with unsigned component<td>`e1 % e2` : *T*<td>Component-wise unsigned integer modulus (OpUMod)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *IntVec* with signed component<td>`e1 % e2` : *T*<td>Component-wise signed integer remainder (OpSMod)
  <tr><td>*e1* : *T*<br> *e2* : *T*<br> *T* is *FloatVec*<td>`e1 % e2` : *T*<td>Component-wise floating point modulus (OpFMod)
</table>

<table class='data'>
  <caption>Binary arithmetic expressions with mixed scalar, vector, and matrix operands</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : f32<br>
          *e2* : *T*<br>
          *T* is *FloatVec*
      <td>`e1 * e2` : *T*<br>
          `e2 * e1` : *T*
      <td>Multiplication of a vector and a scalar (OpVectorTimesScalar)
  <tr><td>*e1* : f32<br>
          *e2* : *T*<br>
          *T* is mat*N*x*M*&lt;f32&gt;
      <td>`e1 * e2` : *T*<br>
          `e2 * e1` : *T*
      <td>Multiplication of a matrix and a scalar (OpMatrixTimesScalar)
  <tr><td>*e1* : vec*M*&lt;f32&gt;<br>
          *e2* : mat*N*x*M*&lt;f32&gt;
      <td>`e1 * e2` : vec*N*&lt;f32&gt;<br>
      <td>Vector times matrix (OpVectorTimesMatrix)
  <tr><td>*e1* : mat*N*x*M*&lt;f32&gt;<br>
          *e2* : vec*N*&lt;f32&gt;
      <td>`e1 * e2` : vec*M*&lt;f32&gt;<br>
      <td>Matrix times vector (OpMatrixTimesVector)
  <tr><td>*e1* : mat*K*x*N*&lt;f32&gt;<br>
          *e2* : mat*M*x*K*&lt;f32&gt;<br>
      <td>`e1 * e2` : mat*M*x*N*&lt;f32&gt;<br>
      <td>Matrix times matrix (OpMatrixTimesMatrix)
</table>

## Comparison Expressions TODO ## {#comparison-expr}

<table class='data'>
  <caption>Comparisons over scalars</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : bool<br>
          *e2* : bool<br>
       <td class="nowrap">`e1 == e2` : bool
       <td>Equality (OpLogicalEqual)
  <tr><td>*e1* : bool<br>
          *e2* : bool<br>
       <td class="nowrap">`e1 != e2` : bool
       <td>Inequality (OpLogicalNotEqual)
  <tr><td>*e1* : i32<br>
          *e2* : i32<br>
       <td class="nowrap">`e1 == e2` : bool
       <td>Equality (OpIEqual)
  <tr><td>*e1* : i32<br>
          *e2* : i32<br>
       <td class="nowrap">`e1 != e2` : bool
       <td>Inequality (OpINotEqual)
  <tr><td>*e1* : i32<br>
          *e2* : i32<br>
       <td class="nowrap">`e1 < e2` : bool
       <td>Less than (OpSLessThan)
  <tr><td>*e1* : i32<br>
          *e2* : i32<br>
       <td class="nowrap">`e1 <= e2` : bool
       <td>Less than or equal (OpSLessThanEqual)
  <tr><td>*e1* : i32<br>
          *e2* : i32<br>
       <td class="nowrap">`e1 >= e2` : bool
       <td>Greater than or equal (OpSGreaterThanEqual)
  <tr><td>*e1* : i32<br>
          *e2* : i32<br>
       <td class="nowrap">`e1 > e2` : bool
       <td>Greater than or equal (OpSGreaterThan)
  <tr><td>*e1* : u32<br>
          *e2* : u32<br>
       <td class="nowrap">`e1 == e2` : bool
       <td>Equality (OpIEqual)
  <tr><td>*e1* : u32<br>
          *e2* : u32<br>
       <td class="nowrap">`e1 != e2` : bool
       <td>Inequality (OpINotEqual)
  <tr><td>*e1* : u32<br>
          *e2* : u32<br>
       <td class="nowrap">`e1 < e2` : bool
       <td>Less than (OpULessThan)
  <tr><td>*e1* : u32<br>
          *e2* : u32<br>
       <td class="nowrap">`e1 <= e2` : bool
       <td>Less than or equal (OpULessThanEqual)
  <tr><td>*e1* : u32<br>
          *e2* : u32<br>
       <td class="nowrap">`e1 >= e2` : bool
       <td>Greater than or equal (OpUGreaterThanEqual)
  <tr><td>*e1* : u32<br>
          *e2* : u32<br>
       <td class="nowrap">`e1 > e2` : bool
       <td>Greater than or equal (OpUGreaterThan)
  <tr><td>*e1* : f32<br>
          *e2* : f32<br>
       <td class="nowrap">`e1 == e2` : bool
       <td>Equality (OpFOrdEqual)
  <tr><td>*e1* : f32<br>
          *e2* : f32<br>
       <td class="nowrap">`e1 != e2` : bool
       <td>Equality (OpFOrdNotEqual)
  <tr><td>*e1* : f32<br>
          *e2* : f32<br>
       <td class="nowrap">`e1 < e2` : bool
       <td>Less than (OpFOrdLessThan)
  <tr><td>*e1* : f32<br>
          *e2* : f32<br>
       <td class="nowrap">`e1 <= e2` : bool
       <td>Less than or equal (OpFOrdLessThanEqual)
  <tr><td>*e1* : f32<br>
          *e2* : f32<br>
       <td class="nowrap">`e1 >= e2` : bool
       <td>Greater than or equal (OpFOrdGreaterThanEqual)
  <tr><td>*e1* : f32<br>
          *e2* : f32<br>
       <td class="nowrap">`e1 > e2` : bool
       <td>Greater than or equal (OpFOrdGreaterThan)
</table>

<table class='data'>
  <caption>Comparisons over vectors</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;bool&gt;
       <td class="nowrap">`e1 == e2` : vec*N*&lt;bool&gt;
       <td>Component-wise equality<br>
           Component |i| of the result is `(`|e1|`[`|i|`] == `|e2|`[`|i|`])`<br>
           (OpLogicalEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;bool&gt;
       <td class="nowrap">`e1 != e2` : vec*N*&lt;bool&gt;
       <td>Component-wise inequality<br>
           Component |i| of the result is `(`|e1|`[`|i|`] != `|e2|`[`|i|`])`<br>
           (OpLogicalNotEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;i32&gt;
       <td class="nowrap">`e1 == e2` : vec*N*&lt;bool&gt;
       <td>Component-wise equality (OpIEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;i32&gt;
       <td class="nowrap">`e1 != e2` : vec*N*&lt;bool&gt;
       <td>Component-wise inequality (OpINotEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;i32&gt;
       <td class="nowrap">`e1 < e2` : vec*N*&lt;bool&gt;
       <td>Component-wise less than (OpSLessThan)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;i32&gt;
       <td class="nowrap">`e1 <= e2` : vec*N*&lt;bool&gt;
       <td>Component-wise less than or equal (OpSLessThanEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;i32&gt;
       <td class="nowrap">`e1 >= e2` : vec*N*&lt;bool&gt;
       <td>Component-wise greater than or equal (OpSGreaterThanEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;i32&gt;
       <td class="nowrap">`e1 > e2` : vec*N*&lt;bool&gt;
       <td>Component-wise greater than or equal (OpSGreaterThan)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;u32&gt;
       <td class="nowrap">`e1 == e2` : vec*N*&lt;bool&gt;
       <td>Component-wise equality (OpIEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;u32&gt;
       <td class="nowrap">`e1 != e2` : vec*N*&lt;bool&gt;
       <td>Component-wise inequality (OpINotEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;u32&gt;
       <td class="nowrap">`e1 < e2` : vec*N*&lt;bool&gt;
       <td>Component-wise less than (OpULessThan)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;u32&gt;
       <td class="nowrap">`e1 <= e2` : vec*N*&lt;bool&gt;
       <td>Component-wise less than or equal (OpULessThanEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;u32&gt;
       <td class="nowrap">`e1 >= e2` : vec*N*&lt;bool&gt;
       <td>Component-wise greater than or equal (OpUGreaterThanEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;u32&gt;
       <td class="nowrap">`e1 > e2` : vec*N*&lt;bool&gt;
       <td>Component-wise greater than or equal (OpUGreaterThan)
          *T* is vec*N*&lt;u32&gt;
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;f32&gt;
       <td class="nowrap">`e1 == e2` : vec*N*&lt;bool&gt;
       <td>Component-wise equality (OpFOrdEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;f32&gt;
       <td class="nowrap">`e1 != e2` : vec*N*&lt;bool&gt;
       <td>Component-wise inequality (OpFOrdNotEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;f32&gt;
       <td class="nowrap">`e1 < e2` : vec*N*&lt;bool&gt;
       <td>Component-wise less than (OpFOrdLessThan)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;f32&gt;
       <td class="nowrap">`e1 <= e2` : vec*N*&lt;bool&gt;
       <td>Component-wise less than or equal (OpFOrdLessThanEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;f32&gt;
       <td class="nowrap">`e1 >= e2` : vec*N*&lt;bool&gt;
       <td>Component-wise greater than or equal (OpFOrdGreaterThanEqual)
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is vec*N*&lt;f32&gt;
       <td class="nowrap">`e1 > e2` : vec*N*&lt;bool&gt;
       <td>Component-wise greater than or equal (OpFOrdGreaterThan)
</table>

## Bit Expressions TODO ## {#bit-expr}

Issue: (dneto): Bitwise-complement is under discussion.  https://github.com/gpuweb/gpuweb/pull/727

<table class='data'>
  <caption>Binary bitwise operations</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is *Integral*
       <td class="nowrap">`e1 | e2` : *T*
       <td>Bitwise-or
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is *Integral*
       <td class="nowrap">`e1 & e2` : *T*
       <td>Bitwise-and
  <tr><td>*e1* : *T*<br>
          *e2* : *T*<br>
          *T* is *Integral*
       <td class="nowrap">`e1 ^ e2` : *T*
       <td>Bitwise-exclusive-or
</table>


<table class='data'>
  <caption>Bit shift expressions</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr algorithm="scalar shift left"><td>|e1| : |T|<br>
          |e2| : u32<br>
          |T| is *Int*
       <td class="nowrap">|e1| `<<` |e2| : |T|
       <td>Shift left:<br>
           Shift |e1| left, inserting zero bits at the least significant positions,
           and discarding the most significant bits.
           The number of bits to shift is the value of |e2| modulo the bit width of |e1|.<br>
           (OpShiftLeftLogical)
  <tr algorithm="vector shift left"><td>|e1| : vec|N|&lt;|T|&gt;<br>
          |e2| : vec|N|&lt;u32&gt;<br>
          |T| is *Int*
       <td class="nowrap">|e1| `<<` |e2| : vec|N|&lt;|T|&gt;
       <td>Component-wise shift left:<br>
           Component |i| of the result is `(`|e1|`[`|i|`] << `|e2|`[`|i|`])`<br>
           (OpShiftLeftLogical)
  <tr algorithm="scalar logical shift right"><td>|e1| : u32<br>
          |e2| : u32<br>
       <td class="nowrap">|e1| `>>` |e2| `: u32`
       <td >Logical shift right:<br>
           Shift |e1| right, inserting zero bits at the most significant positions,
           and discarding the least significant bits.
           The number of bits to shift is the value of |e2| modulo the bit width of |e1|.
           (OpShiftRightLogical)
  <tr algorithm="vector logical shift right"><td>|e1| : vec|N|&lt;u32&gt;<br>
          |e2| : u32<br>
       <td class="nowrap">|e1| `>>` |e2| : vec|N|&lt;u32&gt;
       <td>Component-wise logical shift right:<br>
           Component |i| of the result is `(`|e1|`[`|i|`] >> `|e2|`[`|i|`])`
           (OpShiftRightLogical)
  <tr algorithm="scalar arithmetic shift right"><td>|e1| : i32<br>
          |e2| : u32<br>
       <td class="nowrap">|e1| `>>` |e2| : i32
       <td>Arithmetic shift right:<br>
           Shift |e1| right, copying the sign bit of |e1| into the most significant positions,
           and discarding the least significant bits.
           The number of bits to shift is the value of |e2| modulo the bit width of |e1|.
           (OpShiftRightArithmetic)
  <tr algorithm="vector arithmetic shift right"><td>|e1| : vec|N|&lt;i32&gt;<br>
          |e2| : vec|N|&lt;u32&gt;<br>
       <td class="nowrap">|e1| `>>` |e2| : vec|N|&lt;i32&gt;
       <td>Component-wise arithmetic shift right:<br>
           Component |i| of the result is `(`|e1|`[`|i|`] >> `|e2|`[`|i|`])`
           (OpShiftRightArithmetic)
</table>

## Function Call Expression TODO ## {#function-call-expr}

TODO: *Stub*. Call to function returning non-void, is an expression.

## Variable or const reference TODO ## {#var-const-ref-expr}

## Pointer Expressions TODO ## {#pointer-expr}

TODO: *Stub*: how to write each of the abstract pointer operations

## Expression Grammar Summary ## {#expression-grammar}

<pre class='def'>
primary_expression
  : (IDENT NAMESPACE)* IDENT
  | type_decl PAREN_LEFT argument_expression_list* PAREN_RIGHT
  | const_literal
  | paren_rhs_statement
  | CAST LESS_THAN type_decl GREATER_THAN paren_rhs_statement
      OpConvertFToU
      OpConvertFToS
      OpConvertSToF
      OpConvertUToF
      OpUConvert
      OpSConvert
      OpFConvert
  | AS LESS_THAN type_decl GREATER_THAN paren_rhs_statement
      OpBitcast

postfix_expression
  :
  | BRACKET_LEFT short_circuit_or_expression BRACKET_RIGHT postfix_expression
  | PAREN_LEFT argument_expression_list* PAREN_RIGHT postfix_expression
  | PERIOD IDENT postfix_expression

argument_expression_list
  : (short_circuit_or_expression COMMA)* short_circuit_or_expression

unary_expression
  : singular_expression
  | MINUS unary_expression
      OpSNegate
      OpFNegate
  | BANG unary_expression
      OpNot

singular_expression
  : primary_expression postfix_expression

multiplicative_expression
  : unary_expression
  | multiplicative_expression STAR unary_expression
      OpVectorTimesScalar
      OpMatrixTimesScalar
      OpVectorTimesMatrix
      OpMatrixTimesVector
      OpMatrixTimesMatrix
      OpIMul
      OpFMul
  | multiplicative_expression FORWARD_SLASH unary_expression
      OpUDiv
      OpSDiv
      OpFDiv
  | multiplicative_expression MODULO unary_expression
      OpUMOd
      OpSMod
      OpFMod

additive_expression
  : multiplicative_expression
  | additive_expression PLUS multiplicative_expression
      OpIAdd
      OpFAdd
  | additive_expression MINUS multiplicative_expression
      OpFSub
      OpISub

shift_expression
  : additive_expression
  | shift_expression SHIFT_LEFT additive_expression
        OpShiftLeftLogical
  | shift_expression SHIFT_RIGHT additive_expression
        OpShiftRightLogical or OpShiftRightArithmetic

relational_expression
  : shift_expression
  | relational_expression LESS_THAN shift_expression
        OpULessThan
        OpFOrdLessThan
  | relational_expression GREATER_THAN shift_expression
        OpUGreaterThan
        OpFOrdGreaterThan
  | relational_expression LESS_THAN_EQUAL shift_expression
        OpULessThanEqual
        OpFOrdLessThanEqual
  | relational_expression GREATER_THAN_EQUAL shift_expression
        OpUGreaterThanEqual
        OpFOrdGreaterThanEqual

equality_expression
  : relational_expression
  | relational_expression EQUAL_EQUAL relational_expression
        OpIEqual
        OpFOrdEqual
  | relational_expression NOT_EQUAL relational_expression
        OpINotEqual
        OpFOrdNotEqual

and_expression
  : equality_expression
  | and_expression AND equality_expression

exclusive_or_expression
  : and_expression
  | exclusive_or_expression XOR and_expression

inclusive_or_expression
  : exclusive_or_expression
  | inclusive_or_expression OR exclusive_or_expression

short_circuit_and_expression
  : inclusive_or_expression
  | short_circuit_and_expression AND_AND inclusive_or_expression

short_circuit_or_expression
  : short_circuit_and_expression
  | short_circuit_or_expression OR_OR short_circuit_and_expression
</pre>


# Statements TODO # {#statements}

## Assignment TODO ## {#assignment}

<pre class='def'>
assignment_statement
  : singular_expression EQUAL short_circuit_or_expression
      If singular_expression is a variable, this maps to OpStore to the variable.
      Otherwise, singular expression is a pointer expression in an Assigning (L-value) context
      which maps to OpAccessChain followed by OpStore
</pre>

### Writing to a variable TODO ### {#writing-to-var}

### Writing to a part of a composite variable TODO ### {#writing-to-part-of-composite}

## Control flow TODO ## {#control-flow}

### Sequence TODO ### {#sequence-statement}

### If/elseif/else Statement TODO ### {#if-statement}

<pre class='def'>
if_statement
  : IF paren_rhs_statement body_statement elseif_statement? else_statement?

elseif_statement
  : ELSE_IF paren_rhs_statement body_statement elseif_statement?

else_statement
  : ELSE body_statement
</pre>


### Switch Statement ### {#switch-statement}

<pre class='def'>
switch_statement
  : SWITCH paren_rhs_statement BRACE_LEFT switch_body+ BRACE_RIGHT

switch_body
  : CASE case_selectors COLON BRACE_LEFT case_body BRACE_RIGHT
  | DEFAULT COLON BRACE_LEFT case_body BRACE_RIGHT

case_selectors
  : const_literal (COMMA const_literal)*

case_body
  :
  | statement case_body
  | FALLTHROUGH SEMICOLON
</pre>

A switch statement transfers control to one of a set of case clauses, or to the `default` clause,
depending the evaluation of a selector expression of a scalar integer type.

If the selector value equals a value in a case selector list, then control is transferred to
the body of that case clause.
If the selector value does not equal any of the case selector values, then control is
transferred to the `default` clause.

Each switch statement must have exactly one default clause.

The case selector values must have the same type as the selector expression.

A literal value must not appear more than once in the case selectors for a switch statement.

Note: The value of the literal is what matters, not the spelling.
For example `0`, `00`, and `0x0000` all denote the zero value.

When control reaches the end of a case body, control normally transfers to the first statement
after the switch statement.
Alternately, executing a `fallthrough` statement transfers control to the body of the next case clause or
default clause, whichever appears next in the switch body.
A `fallthrough` statement must not appear as the last statement in the last clause of a switch.


### Loop Statement ### {#loop-statement}

<pre class='def'>
loop_statement
  : LOOP BRACE_LEFT statements continuing_statement? BRACE_RIGHT
</pre>

The loop construct causes a block of statements, the *loop body*, to execute repeatedly.

This repetition can be interrupted by a [[#break-statement]], `return`, or
`discard`.

Optionally, the last statement in the loop body may be a
[[#continuing-statement]].

Note: The loop statement is one of the biggest differences from other shader
languages.

This design directly expresses loop idioms commonly found in compiled code.
In particular, placing the loop update statements at the end of the loop body
allows them to naturally use values defined in the loop body.

<div class='example' heading='GLSL Loop'>
  <xmp>
    int a = 2;
    for (int i = 0; i < 4; i++) {
      a *= 2;
    }
  </xmp>
</div>

<div class='example' heading="[SHORTNAME] Loop">
  <xmp>
    const a : i32 = 2;
    var i : i32 = 0;      // <1>
    loop {
      if (i >= 4) { break; }

      a = a * 2;

      i = i + 1;
    }
  </xmp>
</div>
* <1> The initialization is listed before the loop.

<div class='example' heading='GLSL Loop with continue'>
  <xmp>
    int a = 2;
    const int step = 1;
    for (int i = 0; i < 4; i += step) {
      if (i % 2 == 0) continue;
      a *= 2;
    }
  </xmp>
</div>

<div class='example' heading="[SHORTNAME] Loop with continue">
  <xmp>
    const a : i32 = 2;
    var i : i32 = 0;
    loop {
      if (i >= 4) { break; }

      const step : i32 = 1;

      i = i + 1;
      if (i % 2 == 0) { continue; }

      a = a * 2;
    }
  </xmp>
</div>

<div class='example' heading="[SHORTNAME] Loop with continue and continuing">
  <xmp>
    const a : i32 = 2;
    var i : i32 = 0;
    loop {
      if (i >= 4) { break; }

      const step : i32 = 1;

      if (i % 2 == 0) { continue; }

      a = a * 2;

      continuing {   // <2>
        i = i + step;
      }
    }
  </xmp>
</div>
* <2> The continue construct is placed at the end of the `loop`

### For Statement ### {#for-statement}

<pre class='def'>
for_statement
  : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT

for_header
  : (variable_statement | assignment_statement | func_call_statement)? SEMICOLON
     short_circuit_or_expression? SEMICOLON
     (assignment_statement | func_call_statement)?
</pre>

The `for(var i : i32 = 0; i < 4; i = i + 1) {}` statement is syntactic sugar on
top of the [[#loop-statement]]. The `for` transforms into loop as:

<div class='example' heading="For to Loop transformation">
  <xmp>
    for(var i : i32 = 0; i < 4; i = i + 1) {
      if (a == 0) {
        continue;
      }
      a = a + 2;
    }

    Converts to:

    { # Introduce new scope for loop variable i
      var i : i32 = 0;
      loop {
        if (!(i < 4)) {
          break;
        }

        if (a == 0) {
          continue;
        }
        a = a + 2;

        continuing {
          i = i + 1;
        }
      }
    }
  </xmp>
</div>


### Break ### {#break-statement}

<pre class='def'>
break_statement
  : BREAK
</pre>

Use a `break` statement to transfer control to the first statement
after the body of the nearest-enclosing [[#loop-statement]]
or [[#switch-statement]].

When a `break` statement is placed such that it would exit from a loop's [[#continuing-statement]],
then:

* The `break` statement must appear as either:
    * The only statement in the true-branch clause of an `if` that has:
        * no `else` clause or an empty `else` clause
        * no `elseif` clauses
    * The only statement in the `else` clause of an `if` that has an empty true-branch clause and no `elseif` clauses.
* That `if` statement must appear last in the `continuing` clause.

<div class='example' heading="[SHORTNAME] Valid loop if-break from a continuing clause">
  <xmp>
    const a : i32 = 2;
    var i : i32 = 0;
    loop {
      const step : i32 = 1;

      if (i % 2 == 0) { continue; }

      a = a * 2;

      continuing {
        i = i + step;
        if (i >= 4) { break; }
      }
    }
  </xmp>
</div>

<div class='example' heading="[SHORTNAME] Valid loop if-else-break from a continuing clause">
  <xmp>
    const a : i32 = 2;
    var i : i32 = 0;
    loop {
      const step : i32 = 1;

      if (i % 2 == 0) { continue; }

      a = a * 2;

      continuing {
        i = i + step;
        if (i < 4) {} else { break; }
      }
    }
  </xmp>
</div>

<div class='example' heading="[SHORTNAME] Invalid breaks from a continuing clause">
  <xmp>
    const a : i32 = 2;
    var i : i32 = 0;
    loop {
      const step : i32 = 1;

      if (i % 2 == 0) { continue; }

      a = a * 2;

      continuing {
        i = i + step;
        break;                                     // Invalid: too early
        if (i < 4) { i = i + 1; } else { break; }  // Invalid: if is too complex, and too early
        if (i >= 4) { break; } else { i = i + 1; } // Invalid: if is too complex
      }
    }
  </xmp>
</div>

### Continue ### {#continue-statement}

<pre class='def'>
continue_statement
  : CONTINUE
</pre>

Use a `continue` statement to transfer control in the nearest-enclosing [[#loop-statement]]:

*  forward to the [[#continuing-statement]] at the end of the body of that loop, if it exists.
*  otherwise backward to the first statement in the loop body, starting the next iteration

A `continue` statement must not be placed such that it would transfer
control to an enclosing [[#continuing-statement]].
(It is a *forward* branch when branching to a `continuing` statement.)

A `continue` statement must not be placed such that it would transfer
control past a declaration used in the targeted continuing construct.

<div class='example' heading="Invalid continue bypasses declaration">
  <xmp>
    var i : i32 = 0;
    loop {
      if (i >= 4) { break; }
      if (i % 2 == 0) { continue; } // <3>

      const step : i32 = 2;

      continuing {
        i = i + step;
      }
    }
  </xmp>
</div>
* <3> The `continue` is invalid because it bypasses the declaration of `step` used in the `continuing` construct

### Continuing Statement ### {#continuing-statement}

<pre class='def'>
continuing_statement:
  : CONTINUING body_statement
</pre>

A *continuing* construct is a block of statements to be executed at the end of a loop iteration.
The construct is optional.

The block of statements must not contain a return or discard statement.

### Return ### {#return-statement}

<pre class='def'>
return_statement
  : RETURN short_circuit_or_expression?
</pre>

A `return` statement ends execution of the current function.
If the function is an entry point, then the current shader invocation
is terminated.
Otherwise, evaluation continues with the next expression or statement after
the evaluation of the call site of the current function invocation.

If the return type of the function is the void type, then the return statement
must not have an expression.
Otherwise the expression must be present, and is called the *return value*.
In this case the call site of this function invocation evaluates to the return value.
The type of the return value must match the return type of the function.


### Discard TODO ### {#discard-statement}

## Function Call Statement TODO ## {#function-call-statement}

<pre class='def'>
func_call_statement
  : IDENT PAREN_LEFT argument_expression_list* PAREN_RIGHT
</pre>

## Statements Grammar Summary ## {#statements-summary}

<pre class='def'>
body_statement:
  : BRACE_LEFT statements BRACE_RIGHT

paren_rhs_statement
  : PAREN_LEFT short_circuit_or_expression PAREN_RIGHT

statements
  : statement*

statement
  : SEMICOLON
  | return_statement SEMICOLON
  | if_statement
  | switch_statement
  | loop_statement
  | for_statement
  | func_call_statement SEMICOLON
  | variable_statement SEMICOLON
  | break_statement SEMICOLON
  | continue_statement SEMICOLON
  | DISCARD SEMICOLON
  | assignment_statement SEMICOLON
  | body_statement
</pre>


# Imports TODO # {#imports}

TODO: *Stub* In the abstract, what is the purpose of an import, and what does it provide.

There is one import provided which is `GLSL.std.450`. All other uses of `import`
will be rejected by [SHORTNAME] as being unknown. All uses of the imported methods must
be prefixed by the import name as provided after the `as` keyword.

<pre class='def'>
import_decl
  : IMPORT STRING_LITERAL AS (IDENT NAMESPACE)* IDENT
</pre>

The methods defined in `GLSL.std.450` become available with the given prefix.
The initial import will add an `OpExtInstImport` instruction to the SPIR-V
module header and each usage of a GLSL method will add the appropriate
`OpExtIns` invocation.

<div class='example' heading='Import'>
  <xmp>
    import "GLSL.std.450" as std::glsl;
      %1 = OpExtInstImport "GLSL.std.450"
  </xmp>
</div>

# Functions TODO # {#functions}

A function declaration may only occur at module scope.
The function name is available for use after its declaration, until the end of the program.

Functions must end with a `return` statement. The return may be given with a
value to be returned.

Function names must be unique over all functions and all variables in the
module.

<pre class='def'>
function_decl
  : function_header body_statement

function_type_decl
  : type_decl
  | VOID

function_header
  : FN IDENT PAREN_LEFT param_list PAREN_RIGHT ARROW function_type_decl

param_list
  :
  | (variable_ident_decl COMMA)* variable_ident_decl
</pre>

<div class='example' heading='Function'>
  <xmp>
    void
        %6 = OpTypeVoid

    fn my_func(i : i32, b : f32) -> i32 {
      return 2;
    }

               OpName %my_func "my_func"
               OpName %a "a"
               OpName %b "b"
    %my_func = OpFunction %int None %10
          %a = OpFunctionParameter %_ptr_Function_int
          %b = OpFunctionParameter %_ptr_Function_float
         %14 = OpLabel
               OpReturnValue %int_2
               OpFunctionEnd
  </xmp>
</div>


## Function declaration TODO ## {#function-declaration}

TODO: *Stub*

The names in the parameter list of a function definition are available for use in the body
of the function.
During a particular function evaluation,
the parameter names denote the values specified to the function call expression or statement
which initiated the function evaluation;
the names and values are associated by position.

## Function calls TODO ## {#func-call-semantics}

## Restrictions TODO ## {#function-restriction}
TODO: *This is a stub*

* Recursion is not permitted. (No cycle in the call graph.)
* Function call parameters
 * Match type and number
 * Restrictions on pointers
 * Aliasing (?)


# Entry Points TODO # {#entry-points}

## Entry point declaration TODO ## {#entry-point-decl}
The `entry_point` declares an entry point into the module. The entry points may
be forward declarations but the functions referenced must be declared in the
file.

The input and output parameters to the entry point are determined by which
global variables are used in the function and any called functions.

The entry point function must be declared with no arguments and returning `void`.

<pre class='def'>
entry_point_decl:
   : ENTRY_POINT pipeline_stage EQUAL IDENT
   | ENTRY_POINT pipeline_stage AS STRING_LITERAL EQUAL IDENT
   | ENTRY_POINT pipeline_stage AS IDENT EQUAL IDENT

pipeline_stage
  : VERTEX
  | FRAGMENT
  | COMPUTE
</pre>

<div class='example' heading='Entry Point'>
  <xmp>
    entry_point vertex = main
       OpEntryPoint Vertex %vtx_main "vtx_main" %gl_FragColor

    entry_point fragment as “frag_main” = main
       OpEntryPoint Fragment %main "frag_main" %gl_FragColor

    entry_point compute = comp_main
       OpEntryPoint GLCompute %comp_main "comp_main" %gl_FragColor
  </xmp>
</div>

## Shader Stages TODO ## {#shader-stages}

## Shader Interface TODO ## {#shader-interface}

### Built-in variables TODO ### {#builtin-var-interface}

### Pipeline Input and Output Interface TODO ### {#pipeline-inputs-outputs}

#### Built-in inputs and outputs TODO #### {#builtin-inputs-outputs}
TODO: *Stub*. Forward reference to list of builtin variables.

#### User Data TODO #### {#user-data}

#### Input-output Locations TODO #### {#input-output-locations}
TODO: *Stub*. Location-sizing of types, non-overlap among variables referenced within an entry point static call tree.

### Resource interface TODO ### {#resource-interface}

## Pipeline compatibility TODO ## {#pipeline-compatibility}

### Input-output matching rules TODO ### {#input-output-matching}

# WGSL program TODO # {#wgsl-module}

TODO: *Stub* A WGSL program is a sequence of module-scope declarations.

<pre class='def'>
translation_unit
  : global_decl* EOF
</pre>

<pre class='def'>
global_decl
  : SEMICOLON
  | import_decl SEMICOLON
  | global_variable_decl SEMICOLON
  | global_constant_decl SEMICOLON
  | entry_point_decl SEMICOLON
  | type_alias SEMICOLON
  | struct_decl SEMICOLON
  | function_decl
</pre>


# Execution TODO # {#execution}

## Invocation of an entry point TODO ## {#invocation-of-an-entry-point}

### Before an entry point begins TODO ### {#before-entry-point-begins}

TODO: *Stub*

* Setting values of builtin variables
* External-interface varibales have initialized backing storage
* Internal module-scope variables have backing storage
  * Initializers evaluated in textual order
* No two variables have overlapping storage (might already be covered earlier?)

### Program order (within a thread) TODO ### {#program-order}

#### Function-scope variable lifetime and initialization TODO #### {#function-scope-variable-lifetime}

#### Statement order TODO #### {#statement-order}

#### Intra-statement order (or lack) TODO #### {#intra-statement-order}

TODO: *Stub*: Expression evaluation

## Uniformity TODO ## {#uniformity}

### Uniform control flow TODO ### {#uniform-control-flow}

### Divergence and reconvergence TODO ### {#divergence-reconvergence}

### Uniformity restrictions TODO ### {#uniformity-restrictions}

## Collective operations TODO ## {#collective-operations}

### Barrier TODO ### {#barrier}

### Image Operations Requireing Uniformity TODO ### {#image-operations-requiring-uniformity}

### Derivatives TODO ### {#derivatives}

### Arrayed resource access TODO ### {#arrayed-resource-access}

## Floating point evaluation TODO ## {#floating-point-evaluation}

TODO: *Stub*

* Infinities, NaNs, negative zeros
* Denorms, flushing
* fast-math rules: e.g. reassociation, fusing
* Invariance (or is this more general than floating point)
* Rounding
* Error bounds on basic operations

# Memory Model TODO # {#memory-model}

# Keyword and Token Summary # {#grammar}

## Keyword Summary ## {#keyword-summary}

<table class='data'>
  <caption>Type-defining keywords</caption>
  <thead>
    <tr><td>Token<td>Definition
  </thead>
  <tr><td>`ARRAY`<td>array
  <tr><td>`BOOL`<td>bool
  <tr><td>`FLOAT32`<td>f32
  <tr><td>`INT32`<td>i32
  <tr><td>`MAT2x2`<td>mat2x2  # 2 column x 2 row
  <tr><td>`MAT2x3`<td>mat2x3  # 2 column x 3 row
  <tr><td>`MAT2x4`<td>mat2x4  # 2 column x 4 row
  <tr><td>`MAT3x2`<td>mat3x2  # 3 column x 2 row
  <tr><td>`MAT3x3`<td>mat3x3  # 3 column x 3 row
  <tr><td>`MAT3x4`<td>mat3x4  # 3 column x 4 row
  <tr><td>`MAT4x2`<td>mat4x2  # 4 column x 2 row
  <tr><td>`MAT4x3`<td>mat4x3  # 4 column x 3 row
  <tr><td>`MAT4x4`<td>mat4x4  # 4 column x 4 row
  <tr><td>`POINTER`<td>ptr
  <tr><td>`SAMPLER`<td>sampler
  <tr><td>`SAMPLER_COMPARISON`<td>sampler_comparison
  <tr><td>`STRUCT`<td>struct
  <tr><td>`TEXTURE_SAMPLED_1D`<td>texture_sampled_1d
  <tr><td>`TEXTURE_SAMPLED_1D_ARRAY`<td>texture_sampled_1d_array
  <tr><td>`TEXTURE_SAMPLED_2D`<td>texture_sampled_2d
  <tr><td>`TEXTURE_SAMPLED_2D_ARRAY`<td>texture_sampled_2d_array
  <tr><td>`TEXTURE_SAMPLED_2D_MS`<td>texture_sampled_2d_ms
  <tr><td>`TEXTURE_SAMPLED_2D_MS_ARRAY`<td>texture_sampled_2d_ms_array
  <tr><td>`TEXTURE_SAMPLED_3D`<td>texture_sampled_3d
  <tr><td>`TEXTURE_SAMPLED_CUBE`<td>texture_sampled_cube
  <tr><td>`TEXTURE_SAMPLED_CUBE_ARRAY`<td>texture_sampled_cube_array
  <tr><td>`TEXTURE_RO_1D`<td>texture_ro_1d
  <tr><td>`TEXTURE_RO_1D_ARRAY`<td>texture_ro_1d_array
  <tr><td>`TEXTURE_RO_2D`<td>texture_ro_2d
  <tr><td>`TEXTURE_RO_2D_ARRAY`<td>texture_ro_2d_array
  <tr><td>`TEXTURE_RO_3D`<td>texture_ro_3d
  <tr><td>`TEXTURE_WO_1D`<td>texture_wo_1d
  <tr><td>`TEXTURE_WO_1D_ARRAY`<td>texture_wo_1d_array
  <tr><td>`TEXTURE_WO_2D`<td>texture_wo_2d
  <tr><td>`TEXTURE_WO_2D_ARRAY`<td>texture_wo_2d_array
  <tr><td>`TEXTURE_WO_3D`<td>texture_wo_3d
  <tr><td>`TEXTURE_DEPTH_2D`<td>texture_depth_2d
  <tr><td>`TEXTURE_DEPTH_2D_ARRAY`<td>texture_depth_2d_array
  <tr><td>`TEXTURE_DEPTH_CUBE`<td>texture_depth_cube
  <tr><td>`TEXTURE_DEPTH_CUBE_ARRAY`<td>texture_depth_cube_array
  <tr><td>`UINT32`<td>u32
  <tr><td>`VEC2`<td>vec2
  <tr><td>`VEC3`<td>vec3
  <tr><td>`VEC4`<td>vec4
  <tr><td>`VOID`<td>void
</table>
<table class='data'>
  <caption>Other keywords</caption>
  <thead>
    <tr><td>Token<td>Definition
  </thead>
  <tr><td>`AS`<td>as
  <tr><td>`BINDING`<td>binding
  <tr><td>`BLOCK`<td>block
  <tr><td>`BREAK`<td>break
  <tr><td>`BUILTIN`<td>builtin
  <tr><td>`CASE`<td>case
  <tr><td>`CAST`<td>cast
  <tr><td>`COMPUTE`<td>compute
  <tr><td>`CONST`<td>const
  <tr><td>`CONSTANT_ID`<td>constant_id
  <tr><td>`CONTINUE`<td>continue
  <tr><td>`CONTINUING`<td>continuing
  <tr><td>`DEFAULT`<td>default
  <tr><td>`DISCARD`<td>discard
  <tr><td>`ELSE`<td>else
  <tr><td>`ELSE_IF`<td>elseif
  <tr><td>`ENTRY_POINT`<td>entry_point
  <tr><td>`FALLTHROUGH`<td>fallthrough
  <tr><td>`FALSE`<td>false
  <tr><td>`FN`<td>fn
  <tr><td>`FOR`<td>for
  <tr><td>`FRAGMENT`<td>fragment
  <tr><td>`FUNCTION`<td>function
  <tr><td>`IF`<td>if
  <tr><td>`IMAGE`<td>image
  <tr><td>`IMPORT`<td>import
  <tr><td>`IN`<td>in
  <tr><td>`LOCATION`<td>location
  <tr><td>`LOOP`<td>loop
  <tr><td>`OFFSET`<td>offset
  <tr><td>`OUT`<td>out
  <tr><td>`PRIVATE`<td>private
  <tr><td>`RETURN`<td>return
  <tr><td>`SET`<td>set
  <tr><td>`STORAGE_BUFFER`<td>storage_buffer
  <tr><td>`STRIDE`<td>stride
  <tr><td>`SWITCH`<td>switch
  <tr><td>`TRUE`<td>true
  <tr><td>`TYPE`<td>type
  <tr><td>`UNIFORM`<td>uniform
  <tr><td>`UNIFORM_CONSTANT`<td>uniform_constant
  <tr><td>`VAR`<td>var
  <tr><td>`VERTEX`<td>vertex
  <tr><td>`WORKGROUP`<td>workgroup
</table>
<table class='data'>
  <caption>Image format keywords</caption>
  <thead>
    <tr><td>Token<td>Definition
  </thead>
  <tr><td>`R8UNORM`<td>r8unorm
  <tr><td>`R8SNORM`<td>r8snorm
  <tr><td>`R8UINT`<td>r8uint
  <tr><td>`R8SINT`<td>r8sint
  <tr><td>`R16UINT`<td>r16uint
  <tr><td>`R16SINT`<td>r16sint
  <tr><td>`R16FLOAT`<td>r16float
  <tr><td>`RG8UNORM`<td>rg8unorm
  <tr><td>`RG8SNORM`<td>rg8snorm
  <tr><td>`RG8UINT`<td>rg8uint
  <tr><td>`RG8SINT`<td>rg8sint
  <tr><td>`R32UINT`<td>r32uint
  <tr><td>`R32SINT`<td>r32sint
  <tr><td>`R32FLOAT`<td>r32float
  <tr><td>`RG16UINT`<td>rg16uint
  <tr><td>`RG16SINT`<td>rg16sint
  <tr><td>`RG16FLOAT`<td>rg16float
  <tr><td>`RGBA8UNORM`<td>rgba8unorm
  <tr><td>`RGBA8UNORM-SRGB`<td>rgba8unorm_srgb
  <tr><td>`RGBA8SNORM`<td>rgba8snorm
  <tr><td>`RGBA8UINT`<td>rgba8uint
  <tr><td>`RGBA8SINT`<td>rgba8sint
  <tr><td>`BGRA8UNORM`<td>bgraunorm
  <tr><td>`BGRA8UNORM-SRGB`<td>bgra8unorm_srgb
  <tr><td>`RGB10A2UNORM`<td>rgb10a2unorm
  <tr><td>`RG11B10FLOAT`<td>rg11b10float
  <tr><td>`RG32UINT`<td>rg32uint
  <tr><td>`RG32SINT`<td>rg32sint
  <tr><td>`RG32FLOAT`<td>rg32float
  <tr><td>`RGBA16UINT`<td>rgba16uint
  <tr><td>`RGBA16SINT`<td>rgba16sint
  <tr><td>`RGBA16FLOAT`<td>rgba16float
  <tr><td>`RGBA32UINT`<td>rgba32uint
  <tr><td>`RGBA32SINT`<td>rgba32sint
  <tr><td>`RGBA32FLOAT`<td>rgba32float
</table>

## Reserved Keywords ## {#reserved-keywords}
The following is a list of keywords which are reserved for future expansion.

<table class='data'>
  <tr>
    <td>asm
    <td>bf16
    <td>do
    <td>enum
    <td>f16
  <tr>
    <td>f64
    <td>i8
    <td>i16
    <td>i64
    <td>let
  <tr>
    <td>typedef
    <td>u8
    <td>u16
    <td>u64
    <td>unless
  <tr>
    <td>using
    <td>while
    <td>regardless
    <td>premerge
</table>

## Syntactic Tokens ## {#syntactic-tokens}
<table class='data'>
  <tr><td>`AND`<td>`&`
  <tr><td>`AND_AND`<td>`&&`
  <tr><td>`ARROW`<td>`->`
  <tr><td>`ATTR_LEFT`<td>`[[`
  <tr><td>`ATTR_RIGHT`<td>`]]`
  <tr><td>`FORWARD_SLASH`<td>`/`
  <tr><td>`BANG`<td>`!`
  <tr><td>`BRACKET_LEFT`<td>`[`
  <tr><td>`BRACKET_RIGHT`<td>`]`
  <tr><td>`BRACE_LEFT`<td>`{`
  <tr><td>`BRACE_RIGHT`<td>`}`
  <tr><td>`COLON`<td>`:`
  <tr><td>`COMMA`<td>`,`
  <tr><td>`EQUAL`<td>`=`
  <tr><td>`EQUAL_EQUAL`<td>`==`
  <tr><td>`NOT_EQUAL`<td>`!=`
  <tr><td>`GREATER_THAN`<td>`>`
  <tr><td>`GREATER_THAN_EQUAL`<td>`>=`
  <tr><td>`SHIFT_RIGHT`<td>`>>`
  <tr><td>`LESS_THAN`<td>`<`
  <tr><td>`LESS_THAN_EQUAL`<td>`<=`
  <tr><td>`SHIFT_LEFT`<td>`<<`
  <tr><td>`MODULO`<td>`%`
  <tr><td>`MINUS`<td>`-`
  <tr><td>`NAMESPACE`<td>`::`
  <tr><td>`PERIOD`<td>`.`
  <tr><td>`PLUS`<td>`+`
  <tr><td>`OR`<td>`|`
  <tr><td>`OR_OR`<td>`||`
  <tr><td>`PAREN_LEFT`<td>`(`
  <tr><td>`PAREN_RIGHT`<td>`)`
  <tr><td>`SEMICOLON`<td>`;`
  <tr><td>`STAR`<td>`*`
  <tr><td>`XOR`<td>`^`
</table>


# Validation # {#validation}

TODO: Move these to the subject-matter sections.

Each validation item will be given a unique ID and a test must be provided
when the validation is added. The tests will reference the validation ID in
the test name.

* v-0001: Only allowed import is “GLSL.std.450”
* v-0002: Functions must end with a return statement.
* v-0003: At least one of vertex, fragment or compute shader must be present.
* v-0004: Recursion is not allowed.
* v-0005: Functions must be declared before use.
* v-0006: Variables must be defined before use.
* v-0007: Structures must be defined before use.
* v-0008: All members of a switch must end with a return, break or fallthrough.
* v-0009: break is only permitted in loop and switch constructs.
* v-0010: continue only permitted in loop
* v-0011: Global variable names must be unique
* v-0012: Structure names must be unique
* v-0013: Variables declared in a function must be unique between that function
          and any global variables.
* v-0014: Variables declared in a function must have unique names
* v-0015: Runtime arrays may only appear as the last member of a struct
* v-0016: Function names must be unique
* v-0017: Builtin decorations must have the correct types
* v-0018: Builtin decorations must be used with the correct shader type and
          storage class
* v-0019: Functions used in entry points must exist
* v-0020: The pair of `<entry point name, pipeline stage>` must be unique in the
          module
* v-0021: Can not re-assign a constant.
* v-0022: Global variables must have a storage class
* v-0023: Entry point functions accept no parameters
* v-0024: Entry point functions return void


# Built-in variables TODO # {#builtin-variables}

<div class='example' heading="Valid Built-in Decoration Identifiers">
  <xmp>
    [[builtin position]]
          OpDecorate %gl_Position BuiltIn Position

    [[builtin vertex_idx]]
          OpDecorate %gl_VertexIdx BuiltIn VertexIndex

    [[builtin instance_idx]]
          OpDecorate %gl_InstanceId BuiltIn InstanceIndex

    [[builtin front_facing]]
          OpDecorate %gl_FrontFacing BuiltIn FrontFacing

    [[builtin frag_coord]]
          OpDecorate %gl_FragCoord BuiltIn FragCoord

    [[builtin frag_depth]]
          OpDecorate %gl_FragDepth BuiltIn FragDepth

    [[builtin local_invocation_id]]
          OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId

    [[builtin local_invocation_idx]]
          OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex

    [[builtin global_invocation_id]]
          OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
  </xmp>
</div>

The usages of the variable builtin decorations is further restricted in the
type, function decorations and storage class.

TODO: list storage class and shader stage restrictions.

<table class='data' caption='Copy of WebGPU SPIR-V Environment Spec: Built-In Variables'>
  <thead>
    <tr><td>Name<td>Type<td>Restrictions
  </thead>
    <tr><td>position<td>vec4&ltf32&gt<td>Vertex Output
    <tr><td>vertex_idx<td>i32<td>Vertex Input
    <tr><td>instance_idx<td>i32<td>Vertex Input
    <tr><td>front_facing<td>bool<td>Fragment Input
    <tr><td>frag_coord<td>vec4&ltf32&gt<td>Fragment Input
    <tr><td>frag_depth<td>f32<td>Fragment Output
    <tr><td>local_invocation_id<td>vec3&ltu32&gt<td>Compute Input
    <tr><td>global_invocation_id<td>vec3&ltu32&gt<td>Compute Input
    <tr><td>local_invocation_idx<td>u32<td>Compute Input
</table>

# Built-in functions # {#builtin-functions}

Certain functions are always available in a [SHORTNAME] program,
and are provided by the implementation.
These are called *built-in functions*.

Since a built-in function is always in scope, it is an error to attempt to redefine
one or to use the name of a built-in function as an identifier for any other
kind of declaration.

Unlike ordinary functions defined in a [SHORTNAME] program,
a built-in function may use the same function name with different
sets of parameters.
In other words, a built-in function may have more than one *overload*,
but ordinary function definitions in [SHORTNAME] may not.

When calling a built-in function, all arguments to the function are evaluated
before function evaulation begins.

TODO(dneto): Elaborate the descriptions of the built-in functions.  So far I've only reorganized
the contents of the existing table.

## Logical built-in functions ## {#logical-builtin-functions}

<table class='data'>
  <thead>
    <tr><td>Logical built-in functions<td>SPIR-V
  </thead>
  <tr><td>all(BoolVec) -&gt; bool<td>OpAll
  <tr><td>any(BoolVec) -&gt; bool<td>OpAny
  <tr><td>select(*T*,*T*,bool) -&gt; *T*<td>
       For scalar or vector type *T*.
       `select(a,b,c)` evaluates to *a* when *c* is true, and *b* otherwise.<br>
       OpSelect
  <tr><td>select(vec*N*&lt;*T*&gt;,vec*N*&lt;*T*&gt;,vec*N*&lt;bool&gt;) -&gt; vec*N*&lt;*T*&gt;<td>
       For scalar type *T*.
       `select(a,b,c)` evaluates to a vector with component *i* being `select(a[i], b[i], c[i])`.<br>
       OpSelect
</table>

## Value-testing built-in functions ## {#value-testing-builtin-functions}

<table class='data'>
  <thead>
    <tr><td>Value-testing built-in functions<td>SPIR-V
  </thead>
  <tr><td>is_finite(float) -&gt; bool<td>OpIsFinite
  <tr><td>is_inf(float) -&gt; bool<td>OpIsInf
  <tr><td>is_nan(float) -&gt; bool<td>OpIsNan
  <tr><td>is_normal(float) -&gt; bool<td>OpIsNormal
</table>


TODO: deduplicate these tables
<table class='data'>
  <caption>Unary operators</caption>
  <thead>
    <tr><td>Precondition<td>Conclusion<td>Notes
  </thead>
  <tr><td>*e* : f32<td>`is_nan(e)` : bool<td>OpIsNan
  <tr><td>*e* : *T*, *T* is *FloatVec*<td>`is_nan(e)` : bool<*N*>, where *N = Arity(T)*<td>OpIsNan
  <tr><td>*e* : f32<td>`is_inf(e)` : bool<td>OpIsInf
  <tr><td>*e* : *T*, *T* is *FloatVec*<td>`is_inf(e)` : bool<*N*>, where *N = Arity(T)*<td>OpIsInf
  <tr><td>*e* : f32<td>`is_finite(e)` : bool<td>OpIsFinite
  <tr><td>*e* : *T*, *T* is *FloatVec*<td>`is_finite(e)` : bool<*N*>, where *N = Arity(T)*<td>OpIsFinite, or emulate
  <tr><td>*e* : f32<td>`is_normal(e)` : bool<td>OpIsNormal
  <tr><td>*e* : *T*, *T* is *FloatVec*<td>`is_normal(e)` : bool<*N*>, where *N = Arity(T)*<td>OpIsNormal, or emulate
</table>

## Vector built-in functions ## {#vector-builtin-functions}

<table class='data'>
  <thead>
    <tr><td>Vector built-in functions<td>SPIR-V
  </thead>
  <tr><td>dot(vecN&lt;f32&gt;, vecN&lt;f32&gt;) -&gt; float<td>OpDot
  <tr><td>outer_product(vecN&lt;f32&gt;, vecM&lt;f32&gt;) -&gt; matNxM&lt;f32&gt;<td>OpOuterProduct
</table>

## Derivative built-in functions ## {#derivative-builtin-functions}

<table class='data'>
  <thead>
    <tr><td>Derivative built-in functions<td>SPIR-V
  </thead>
  <tr><td>dpdx(IDENT) -&gt; float<td>OpDPdx
  <tr><td>dpdx_coarse(IDENT) -&gt; float<td>OpDPdxCoarse
  <tr><td>dpdx_fine(IDENT) -&gt; float<td>OpDPdxFine
  <tr><td>dpdy(IDENT) -&gt; float<td>OpDPdy
  <tr><td>dpdy_coarse(IDENT) -&gt; float<td>OpDPdyCoarse
  <tr><td>dpdy_fine(IDENT) -&gt; float<td>OpDPdyFine
  <tr><td>fwidth(IDENT) -&gt; float<td>OpFwidth
  <tr><td>fwidth_coarse(IDENT) -&gt; float<td>OpFwidthCoarse
  <tr><td>fwidth_fine(IDENT) -&gt; float<td>OpFwidthFine
</table>

## Texture built-in functions ## {#texture-builtin-functions}

<pre class='def'>
`vec4<type> texture_load(texture_ro, i32 coords, i32 level_of_detail)`
`vec4<type> texture_load(texture_ro, vec2<i32> coords, i32 level_of_detail)`
`vec4<type> texture_load(texture_ro, vec3<i32> coords, i32 level_of_detail)`
  %32 = OpImageFetch %v4float %texture_ro %coords Lod %level_of_detail

TODO(dsinclair): Texture load on a sampled texture

TODO(dsinclair): Texture load on multi-sampled texture

TODO(dsinclair): Add `texture_write` method for texture_wo with integral coords

TODO(dsinclair): Allow a small constant offset on the coordinate? May not be portable.

`vec4<type> texture_sample(texture_sampled, sampler, f32 coords)`
`vec4<type> texture_sample(texture_sampled, sampler, vec2<f32> coords)`
`vec4<type> texture_sample(texture_sampled, sampler, vec3<f32> coords)`
`vec4<type> texture_sample(texture_sampled, sampler, vec4<f32> coords)`
  %24 = OpImageSampleImplicitLod %v4float %sampled_image %coords

`vec4<type> texture_sample_level(texture_sampled, sampler, f32 coords, f32 lod)`
`vec4<type> texture_sample_level(texture_sampled, sampler, vec2<f32> coords, f32 lod)`
`vec4<type> texture_sample_level(texture_sampled, sampler, vec3<f32> coords, f32 lod)`
`vec4<type> texture_sample_level(texture_sampled, sampler, vec4<f32> coords, f32 lod)`
  %25 = OpImageSampleExplicitLod %v4float %sampled_image %coords Lod %lod

`vec4<type> texture_sample_bias(texture_sampled, sampler, f32 coords, f32 bias)`
`vec4<type> texture_sample_bias(texture_sampled, sampler, vec2<f32> coords, f32 bias)`
`vec4<type> texture_sample_bias(texture_sampled, sampler, vec3<f32> coords, f32 bias)`
`vec4<type> texture_sample_bias(texture_sampled, sampler, vec4<f32> coords, f32 bias)`
  %19 = OpImageSampleImplicitLod %v4float %sampled_image %coords Bias %bias

`f32 texture_sample_compare(texture_depth, sampler_comparison, f32 coords, f32 depth_reference)`
`f32 texture_sample_compare(texture_depth, sampler_comparison, vec2<f32> coords, f32 depth_reference)`
`f32 texture_sample_compare(texture_depth, sampler_comparison, vec3<f32> coords, f32 depth_reference)`
  %65 = OpImageSampleDrefImplicitLod %float %sampled_image %coord %depth_reference Lod %float_0

TODO(dsinclair): Add Level-of-Detail via explicit gradient. "Grad" image operand in SPIR-V

TODO(dsinclair): Need gather operations
</pre>

## Atomic built-in functions ## {#atomic-builtin-functions}

# Glossary # {#glossary}

TODO: Remove terms unused in the rest of the specification.

<table class='data'>
  <thead>
    <tr><td>Term<td>Definition
  </thead>
  <tr><td>Dominates
      <td>Basic block `A` *dominates* basic block `B` if:
          * `A` and `B` are both in the same function `F`
          * Every control flow path in `F` that goes to `B` must also to through `A`
  <tr><td>Strictly dominates
      <td>`A` *strictly dominates* `B` if `A` dominates `B` and `A != B`
  <tr><td>DomBy(A)
      <td>The basic blocks dominated by `A`
</table>

# MATERIAL TO BE MOVED TO A NEW HOME OR DELETED # {#junkyard}

## Composite types ## {#composite-types}

A type is *composite* if its values have a well-defined internal
structure of typed *components*.

The following types are *composite types*:

* [[#vector-types]]
* [[#matrix-types]]
* [[#array-types]]
* [[#struct-types]]

[SHORTNAME] has operations for:

* extracting one of the components of a composite value
* creating a new composite value from an old one by replacing one of its components
* creating a new composite value from components

## Type Promotions ## {#type-promotions}
There are no implicit type promotions in [SHORTNAME]. If you want to convert between
types you must use the cast syntax to do it.

<div class='example'>
  <xmp highlight='rust'>
    var e : f32 = 3;    # error: literal is the wrong type

    var f : f32 = 1.0;

    var t : i32 = i32(f);
  </xmp>
</div>

The non-promotion extends to vector classes as well. There are no overrides to
shorten vector declarations based on the type or number of elements provided.
If you want `vec4<f32>` you must provide 4 float values in the constructor.

## Precedence ## {#precedence}

Issue: (dsinclair) Write out precedence rules. Matches c and glsl rules ....

## Preamble ## {#preamble}
[SHORTNAME] is focused on WebGPU shaders. As such, the following is defined for all
shaders which are generated, when translated to SPIR-V.

TODO(dneto): Forcing the Vulkan memory model is obsolete and should be removed.

<div class='example' heading='Preamble'>
  <xmp>
....
OpCapability Shader
OpCapability VulkanMemoryModel
OpMemoryModel Logical VulkanKHR
....
  </xmp>
</div>

While we recognize that most Vulkan devices will not support VulkanMemoryModel
we expect the SPIR-V generated to be converted by SPIRV-Tools after the fact
to make the shader compatible.
